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.
Diffstat (limited to '')
-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())