[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Lua5.3.0-work2: math.random and max integer
- From: cyril Romain <c.romain@...>
- Date: Sun, 06 Apr 2014 12:12:37 +0200
Hi,
In Lua5.3.0-work2 math.random does not support the max integer value. A
range larger than the max integer is also not supported [1].
Reading Lua source code that's something new in lmathlib.c due the new
integer type [2].
Is there a reason for that or is it something in the Lua5.3.0 release
TODO list ?
In case it can help you can find in attachement a patch that fix
(almost) all the value range issues [3].
Thanks in advance for you answer,
Best regards,
Cyril Romain
[1] Lua 5.3.0 (work2):
> max_int = 2^(debug.numbits'i'-1)-1
> return print(math.random(0, max_int))
stdin:1: bad argument #1 to 'random' (interval is empty)
> return print(math.random(-42, max_int-42))
stdin:1: bad argument #1 to 'random' (interval is empty)
[2] lmathlib.c:
up++; /* change interval to [low, up) */
[3] As explained in the patch header, corners cases still exists with a
narrow range around max integer values.
The tests in the test script are far from exhaustive but provided for
convenience.
>From 38cc79bf8a902e935388789f6005db78a95c51d5 Mon Sep 17 00:00:00 2001
From: Cyril Romain <public.cyril@romain.tf>
Date: Sun, 6 Apr 2014 11:09:34 +0200
Subject: [PATCH] Improve math.random
math.random now:
- accepts min and max integer values:
i.e. min=-2^(debug.numbits'i'-1) and max=2^(debug.numbits'i'-1)-1.
- accepts a range larger than the max integer value:
e.g. math.random(-5000, 2^(debug.numbits'i'-1)-1)
- is "symetric to 0", i.e. it does floor positive values and ceil
negative ones:
e.g. math.random(2.5, 2.5) == 3, math.random(-2.5, -2.5) == -3
Corner cases still exists with a narrow range around the max integer.
---
src/lmathlib.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/src/lmathlib.c b/src/lmathlib.c
index a40a6fb..2623ab8 100644
--- a/src/lmathlib.c
+++ b/src/lmathlib.c
@@ -218,7 +218,7 @@ static int math_random (lua_State *L) {
/* the `%' avoids the (rare) case of r==1, and is needed also because on
some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX;
- lua_Integer low, up;
+ lua_Number low, up;
switch (lua_gettop(L)) { /* check number of arguments */
case 0: { /* no arguments */
lua_pushnumber(L, r); /* Number between 0 and 1 */
@@ -226,20 +226,21 @@ static int math_random (lua_State *L) {
}
case 1: { /* only upper limit */
low = 1;
- up = luaL_checkinteger(L, 1);
+ up = luaL_checknumber(L, 1);
break;
}
case 2: { /* lower and upper limits */
- low = luaL_checkinteger(L, 1);
- up = luaL_checkinteger(L, 2);
+ low = luaL_checknumber(L, 1);
+ up = luaL_checknumber(L, 2);
break;
}
default: return luaL_error(L, "wrong number of arguments");
}
/* random integer in the interval [low, up] */
- up++; /* change interval to [low, up) */
- luaL_argcheck(L, up - low > 0, 1, "interval is empty");
- lua_pushinteger(L, (lua_Integer)(r * (lua_Number)(up - low)) + low);
+ luaL_argcheck(L, low <= up, 1, "interval is empty");
+ lua_Number ri = r * up - r * low + low;
+ lua_Integer res = (lua_Integer)((ri < 0) ? l_mathop(ceil)(ri - 0.5) : l_mathop(floor)(ri + 0.5));
+ lua_pushinteger(L, res);
return 1;
}
--
1.9.1
min = -2^(debug.numbits'i'-1)
max = 2^(debug.numbits'i'-1)-1
local t = {min, max, 0, 1, -1, -2, 2, 5000, -809}
math.randomseed(os.time())
for i=1,200 do
assert(math.random(-1, -1) == -1)
assert(math.random(-2, -2) == -2)
assert(math.random(1, 1) == 1)
a = math.random(0, 1)
assert(a == 1 or a == 0)
assert(math.random(2.5, 2.5) == 3)
assert(math.random(-2.5, -2.5) == -3)
assert(math.random(min, min) == min)
--assert(math.random(max, max) == max) this one fails
m, n = math.random(7), math.random(7)
if t[n] >= t[m] then
a = math.random(t[m], t[n])
print('rand('..t[m]..','..t[n]..") -> "..a)
assert(a >= t[m] and a <= t[n])
end
m, n = 1, 2
a = math.random(min, max)
print('rand('..t[m]..','..t[n]..") -> "..a)
assert(a >= t[m] and a <= t[n])
end