aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-12-11 11:34:47 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-12-11 11:34:47 -0200
commit51316f9df7aacb54633a3e9b910a070590ac6259 (patch)
tree954c50a7b11ace095e8a2ca70e31832230e902cb
parent46beca5bed8a7700b18100fe48a78373be5055f9 (diff)
downloadlua-51316f9df7aacb54633a3e9b910a070590ac6259.tar.gz
lua-51316f9df7aacb54633a3e9b910a070590ac6259.tar.bz2
lua-51316f9df7aacb54633a3e9b910a070590ac6259.zip
'math.rand()' uses higher bits to produce float value
The call 'math.rand()' converts the higher bits of the internal unsigned integer random to a float, instead of its lower bits. That ensures that Lua compiled with different float precisions always generates equal (up to the available precision) random numbers when given the same seed.
-rw-r--r--lmathlib.c58
-rw-r--r--testes/math.lua14
2 files changed, 46 insertions, 26 deletions
diff --git a/lmathlib.c b/lmathlib.c
index e8e88e7a..f2bfff9b 100644
--- a/lmathlib.c
+++ b/lmathlib.c
@@ -323,14 +323,18 @@ static Rand64 nextrand (Rand64 *state) {
323 323
324/* 324/*
325** Convert bits from a random integer into a float in the 325** Convert bits from a random integer into a float in the
326** interval [0,1). 326** interval [0,1), getting the higher FIG bits from the
327** random unsigned integer and converting that to a float.
327*/ 328*/
328#define maskFIG (~(~(Rand64)1 << (FIGS - 1))) /* use FIGS bits */ 329
329#define shiftFIG \ 330/* must throw out the extra (64 - FIGS) bits */
330 (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1))) /* 2^(-FIGS) */ 331#define shift64_FIG (64 - FIGS)
332
333/* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */
334#define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1)))
331 335
332static lua_Number I2d (Rand64 x) { 336static lua_Number I2d (Rand64 x) {
333 return (lua_Number)(x & maskFIG) * shiftFIG; 337 return (lua_Number)(trim64(x) >> shift64_FIG) * scaleFIG;
334} 338}
335 339
336/* convert a 'Rand64' to a 'lua_Unsigned' */ 340/* convert a 'Rand64' to a 'lua_Unsigned' */
@@ -449,35 +453,49 @@ static Rand64 nextrand (Rand64 *state) {
449/* an unsigned 1 with proper type */ 453/* an unsigned 1 with proper type */
450#define UONE ((lu_int32)1) 454#define UONE ((lu_int32)1)
451 455
456
452#if FIGS <= 32 457#if FIGS <= 32
453 458
454#define maskHI 0 /* do not need bits from higher half */ 459/* 2^(-FIGS) */
455#define maskLOW (~(~UONE << (FIGS - 1))) /* use FIGS bits */ 460#define scaleFIG (l_mathop(0.5) / (UONE << (FIGS - 1)))
456#define shiftFIG (l_mathop(0.5) / (UONE << (FIGS - 1))) /* 2^(-FIGS) */ 461
462/*
463** get up to 32 bits from higher half, shifting right to
464** throw out the extra bits.
465*/
466static lua_Number I2d (Rand64 x) {
467 lua_Number h = (lua_Number)(trim32(x.h) >> (32 - FIGS));
468 return h * scaleFIG;
469}
457 470
458#else /* 32 < FIGS <= 64 */ 471#else /* 32 < FIGS <= 64 */
459 472
460/* must take care to not shift stuff by more than 31 slots */ 473/* must take care to not shift stuff by more than 31 slots */
461 474
462/* use FIGS - 32 bits from higher half */ 475/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
463#define maskHI (~(~UONE << (FIGS - 33))) 476#define scaleFIG \
477 ((lua_Number)1.0 / (UONE << 30) / 8.0 / (UONE << (FIGS - 33)))
464 478
465/* use 32 bits from lower half */ 479/*
466#define maskLOW (~(~UONE << 31)) 480** use FIGS - 32 bits from lower half, throwing out the other
467 481** (32 - (FIGS - 32)) = (64 - FIGS) bits
468/* 2^(-FIGS) == (1 / 2^33) / 2^(FIGS-33) */ 482*/
469#define shiftFIG ((lua_Number)(1.0 / 8589934592.0) / (UONE << (FIGS - 33))) 483#define shiftLOW (64 - FIGS)
470 484
471#endif 485/*
486** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32)
487*/
488#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * 2.0)
472 489
473#define twoto32 l_mathop(4294967296.0) /* 2^32 */
474 490
475static lua_Number I2d (Rand64 x) { 491static lua_Number I2d (Rand64 x) {
476 lua_Number h = (lua_Number)(x.h & maskHI); 492 lua_Number h = (lua_Number)trim32(x.h) * shiftHI;
477 lua_Number l = (lua_Number)(x.l & maskLOW); 493 lua_Number l = (lua_Number)(trim32(x.l) >> shiftLOW);
478 return (h * twoto32 + l) * shiftFIG; 494 return (h + l) * scaleFIG;
479} 495}
480 496
497#endif
498
481 499
482/* convert a 'Rand64' to a 'lua_Unsigned' */ 500/* convert a 'Rand64' to a 'lua_Unsigned' */
483static lua_Unsigned I2UInt (Rand64 x) { 501static lua_Unsigned I2UInt (Rand64 x) {
diff --git a/testes/math.lua b/testes/math.lua
index 7c780e59..dc5b84f6 100644
--- a/testes/math.lua
+++ b/testes/math.lua
@@ -823,17 +823,19 @@ do
823 assert(random(0) == res) 823 assert(random(0) == res)
824 824
825 math.randomseed(1007, 0) 825 math.randomseed(1007, 0)
826 -- using lower bits to generate random floats; (the '% 2^32' converts 826 -- using higher bits to generate random floats; (the '% 2^32' converts
827 -- 32-bit integers to floats as unsigned) 827 -- 32-bit integers to floats as unsigned)
828 local res 828 local res
829 if floatbits <= 32 then 829 if floatbits <= 32 then
830 -- get all bits from the lower half 830 -- get all bits from the higher half
831 res = (l & ~(~0 << floatbits)) % 2^32 831 res = (h >> (32 - floatbits)) % 2^32
832 else 832 else
833 -- get 32 bits from the lower half and the rest from the higher half 833 -- get 32 bits from the higher half and the rest from the lower half
834 res = ((h & ~(~0 << (floatbits - 32))) % 2^32) * 2^32 + (l % 2^32) 834 res = (h % 2^32) * 2^(floatbits - 32) + ((l >> (64 - floatbits)) % 2^32)
835 end 835 end
836 assert(random() * 2^floatbits == res) 836 local rand = random()
837 assert(eq(rand, 0x0.7a7040a5a323c9d6, 2^-floatbits))
838 assert(rand * 2^floatbits == res)
837end 839end
838 840
839math.randomseed(0, os.time()) 841math.randomseed(0, os.time())