math_random是lua库函数math.random的具体实现。math_random的目的是获取一个伪随机数。math_random允许你通过传入的参数来控制产生的随机数的范围。math_random的声明如下:
static int math_random (lua_State *L);
math_random的实现源码:
static int math_random (lua_State *L) {
lua_Integer low, up;
double r = (double)l_rand() * (1.0 / ((double)L_RANDMAX + 1.0));
switch (lua_gettop(L)) { /* check number of arguments */
case 0: { /* no arguments */
lua_pushnumber(L, (lua_Number)r); /* Number between 0 and 1 */
return 1;
}
case 1: { /* only upper limit */
low = 1;
up = luaL_checkinteger(L, 1);
break;
}
case 2: { /* lower and upper limits */
low = luaL_checkinteger(L, 1);
up = luaL_checkinteger(L, 2);
break;
}
default: return luaL_error(L, "wrong number of arguments");
}
/* random integer in the interval [low, up] */
luaL_argcheck(L, low <= up, 1, "interval is empty");
luaL_argcheck(L, low >= 0 up <= LUA_MAXINTEGER + low, 1,
"interval too large");
r *= (double)(up - low) + 1.0;
lua_pushinteger(L, (lua_Integer)r + low);
return 1;
}
现在分析math_random的实现:
double r = (double)l_rand() * (1.0 / ((double)L_RANDMAX + 1.0));
math_random直接通过l_rand先求得一个随机数,然后将其缩小到\[0,1)之间。注意,这里使用double类型来表示随机数,而不是lua_Number:考虑到兼容性,lua_Number可能是float类型;当lua_Number是float类型时,缩小随机数可能会丢失精度;缩小随机数时应该竟可能地保留精度,这样才能体现更好的随机性。这里(double)L_RANDMAX加1的目的是,保证缩小后的随机数r小于1。 接下来是一个switch语句,对调用者传入的参数做判断,并根据参数的数量和值确定求取随机数范围的上界up和下界low:
接下来执行参数检查:
luaL_argcheck(L, low <= up, 1, "interval is empty");
luaL_argcheck(L, low >= 0 up <= LUA_MAXINTEGER + low, 1,
"interval too large");
需要调用者保证:
然后执行:
r *= (double)(up - low) + 1.0;
这里加1.0的目的是保证r在\[0,up-(low-1)\]内; 然后将r移动到\[low,high\]中:
lua_pushinteger(L, (lua_Integer)r + low);
将r移动到\[low,high\]范围内,得到最终结果,然后将其入栈。