Erik Hollembeak

`lmathlib.c`: Lua Math Library

Lua project logo

Lua Math Library Source

The Lua math library is largely self-contained to one ~200 SLOC file, lmathlib.c. It serves as a straightforward introduction to how structure and present libraries in the Lua runtime.

How is Lua’s math library implemented?

The bulk of the math library functionality is implemented by directly mapping C functions from libC’s math.h to corresponding Lua functions. For example:

static int math_log10 (lua_State *L) {
  lua_pushnumber(L, log10(luaL_checknumber(L, 1)));
  return 1;

maps the libC math function for taking base 10 logarithms into a function math_log10 in the Lua runtime. The syntax for providing that mapping might appear a little strange at first. For starters, what is the lua_State parameter that appears throughout? What are lua_pushnumber and lua_checknumber?

lua_State is defined in lstate.h. It is a struct that represents the runtime state for a Lua thread, including (importantly in this case) the stack state for the thread. This is where arguments for each of the implemented Lua functions are derived from and saved to after execution.

How is Lua’s math library packaged?

At the end of the package, there’s the first instance observed of a pattern for cataloging the provided functions and then registering them with the lua runtime:

A list of structs is explicitly created mapping function names to function implementations. This array is then passed to the luaL_register function when initializing the library to register all of the defined functions.

The pattern for handling args seems to be to defensively check that arguments are in fact numeric prior to evaluation and to push results to the top of the stack. I discovered in testing that lua will coerce string arguments into numbers in at least some cases. to wit:

> math.pow(2, 3)
> math.sin("1")
> math.sin("cat")
stdin:1: bad argument #1 to 'sin' (number expected, got string)
stack traceback:
	[C]: in function 'math.sin'
	stdin:1: in main chunk
	[C]: in ?

Useful numbers like Pi and Infinity are also registered at this time (math.pi and math.huge, respectively).

Also of note in the 5.1.5 source is that backfills for older versions of modular arithmetic are also provided conditionally by using a #define’d flag LUA_COMPAT_MOD. I would guess this pattern will come up again.