diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-03-09 16:23:39 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-03-09 16:23:39 -0300 |
commit | dbec41f34ca26f4762bbda3c6e99ba227508d743 (patch) | |
tree | 8b3fc30445bc508a604a71197f312f8d22ff7d38 /lmathlib.c | |
parent | 0b3db69e4102c148b45a4491ef533ff449b0b927 (diff) | |
download | lua-dbec41f34ca26f4762bbda3c6e99ba227508d743.tar.gz lua-dbec41f34ca26f4762bbda3c6e99ba227508d743.tar.bz2 lua-dbec41f34ca26f4762bbda3c6e99ba227508d743.zip |
random floats of different sizes get exactly needed number of random bits
(up to 64)
Diffstat (limited to 'lmathlib.c')
-rw-r--r-- | lmathlib.c | 88 |
1 files changed, 58 insertions, 30 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lmathlib.c,v 1.121 2018/03/09 14:56:25 roberto Exp roberto $ | 2 | ** $Id: lmathlib.c,v 1.122 2018/03/09 15:05:13 roberto Exp roberto $ |
3 | ** Standard mathematical library | 3 | ** Standard mathematical library |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -10,9 +10,10 @@ | |||
10 | #include "lprefix.h" | 10 | #include "lprefix.h" |
11 | 11 | ||
12 | 12 | ||
13 | #include <float.h> | ||
13 | #include <limits.h> | 14 | #include <limits.h> |
14 | #include <stdlib.h> | ||
15 | #include <math.h> | 15 | #include <math.h> |
16 | #include <stdlib.h> | ||
16 | 17 | ||
17 | #include "lua.h" | 18 | #include "lua.h" |
18 | 19 | ||
@@ -250,11 +251,17 @@ static int math_type (lua_State *L) { | |||
250 | ** =================================================================== | 251 | ** =================================================================== |
251 | */ | 252 | */ |
252 | 253 | ||
254 | /* number of binary digits in the mantissa of a float */ | ||
255 | #define FIGS l_mathlim(MANT_DIG) | ||
253 | 256 | ||
254 | #define twotomin53 (1.0 / 9007199254740992.0) /* 2^-53 */ | 257 | #if FIGS > 64 |
258 | /* there are only 64 random bits; use them all */ | ||
259 | #undef FIGS | ||
260 | #define FIGS 64 | ||
261 | #endif | ||
255 | 262 | ||
256 | 263 | ||
257 | #if defined(LLONG_MAX) && !defined(LUA_DEBUG) /* { */ | 264 | #if !defined(LUA_USE_C89) && defined(LLONG_MAX) && !defined(LUA_DEBUG) /* { */ |
258 | 265 | ||
259 | /* | 266 | /* |
260 | ** Assume long long. | 267 | ** Assume long long. |
@@ -272,15 +279,17 @@ static I xorshift128plus (I *state) { | |||
272 | return state[1] + y; | 279 | return state[1] + y; |
273 | } | 280 | } |
274 | 281 | ||
282 | /* must take care to not shift stuff by more than 63 slots */ | ||
275 | 283 | ||
276 | #define mask53 (~(~0LLU << 53)) | 284 | #define maskFIG (~(~1LLU << (FIGS - 1))) /* use FIGS bits */ |
285 | #define shiftFIG (l_mathop(0.5) / (1LLU << (FIGS - 1))) /* 2^(-FIG) */ | ||
277 | 286 | ||
278 | /* | 287 | /* |
279 | ** Convert 53 bits from a random integer into a double in the | 288 | ** Convert bits from a random integer into a float in the |
280 | ** interval [0,1). | 289 | ** interval [0,1). |
281 | */ | 290 | */ |
282 | static double I2d (I x) { | 291 | static lua_Number I2d (I x) { |
283 | return (x & mask53) * twotomin53; | 292 | return (lua_Number)(x & maskFIG) * shiftFIG; |
284 | } | 293 | } |
285 | 294 | ||
286 | /* convert an 'I' to a lua_Unsigned */ | 295 | /* convert an 'I' to a lua_Unsigned */ |
@@ -289,10 +298,10 @@ static double I2d (I x) { | |||
289 | /* convert a lua_Integer to an 'I' */ | 298 | /* convert a lua_Integer to an 'I' */ |
290 | #define Int2I(x) ((I)(x)) | 299 | #define Int2I(x) ((I)(x)) |
291 | 300 | ||
292 | #else /* }{ */ | 301 | #else /* no long long }{ */ |
293 | 302 | ||
294 | /* | 303 | /* |
295 | ** No long long; Use two 32-bit integers to represent a 64-bit quantity. | 304 | ** Use two 32-bit integers to represent a 64-bit quantity. |
296 | */ | 305 | */ |
297 | 306 | ||
298 | #if LUAI_BITSINT >= 32 | 307 | #if LUAI_BITSINT >= 32 |
@@ -303,7 +312,8 @@ typedef unsigned long lu_int32; | |||
303 | 312 | ||
304 | /* a 64-bit value */ | 313 | /* a 64-bit value */ |
305 | typedef struct I { | 314 | typedef struct I { |
306 | lu_int32 x1, x2; | 315 | lu_int32 h; /* higher half */ |
316 | lu_int32 l; /* lower half */ | ||
307 | } I; | 317 | } I; |
308 | 318 | ||
309 | 319 | ||
@@ -311,31 +321,31 @@ typedef struct I { | |||
311 | ** basic operations on 'I' values | 321 | ** basic operations on 'I' values |
312 | */ | 322 | */ |
313 | 323 | ||
314 | static I pack (int x1, int x2) { | 324 | static I pack (int h, int l) { |
315 | I result; | 325 | I result; |
316 | result.x1 = x1; | 326 | result.h = h; |
317 | result.x2 = x2; | 327 | result.l = l; |
318 | return result; | 328 | return result; |
319 | } | 329 | } |
320 | 330 | ||
321 | /* i ^ (i << n) */ | 331 | /* i ^ (i << n) */ |
322 | static I Ixorshl (I i, int n) { | 332 | static I Ixorshl (I i, int n) { |
323 | return pack(i.x1 ^ ((i.x1 << n) | (i.x2 >> (32 - n))), i.x2 ^ (i.x2 << n)); | 333 | return pack(i.h ^ ((i.h << n) | (i.l >> (32 - n))), i.l ^ (i.l << n)); |
324 | } | 334 | } |
325 | 335 | ||
326 | /* i ^ (i >> n) */ | 336 | /* i ^ (i >> n) */ |
327 | static I Ixorshr (I i, int n) { | 337 | static I Ixorshr (I i, int n) { |
328 | return pack(i.x1 ^ (i.x1 >> n), i.x2 ^ ((i.x2 >> n) | (i.x1 << (32 - n)))); | 338 | return pack(i.h ^ (i.h >> n), i.l ^ ((i.l >> n) | (i.h << (32 - n)))); |
329 | } | 339 | } |
330 | 340 | ||
331 | static I Ixor (I i1, I i2) { | 341 | static I Ixor (I i1, I i2) { |
332 | return pack(i1.x1 ^ i2.x1, i1.x2 ^ i2.x2); | 342 | return pack(i1.h ^ i2.h, i1.l ^ i2.l); |
333 | } | 343 | } |
334 | 344 | ||
335 | static I Iadd (I i1, I i2) { | 345 | static I Iadd (I i1, I i2) { |
336 | I result = pack(i1.x1 + i2.x1, i1.x2 + i2.x2); | 346 | I result = pack(i1.h + i2.h, i1.l + i2.l); |
337 | if (result.x2 < i1.x2) /* carry? */ | 347 | if (result.l < i1.l) /* carry? */ |
338 | result.x1++; | 348 | result.h++; |
339 | return result; | 349 | return result; |
340 | } | 350 | } |
341 | 351 | ||
@@ -355,28 +365,46 @@ static I xorshift128plus (I *state) { | |||
355 | 365 | ||
356 | 366 | ||
357 | /* | 367 | /* |
358 | ** Converts an 'I' into a double, getting its lower half plus 21 | 368 | ** Converts an 'I' into a float. |
359 | ** (53 - 32) bits from its higher half and joining them into a double. | ||
360 | */ | 369 | */ |
361 | 370 | ||
362 | #define mask32 0xffffffff | 371 | #if FIGS <= 32 |
363 | #define mask21 (~(~0U << 21)) | 372 | |
373 | /* do not need bits from higher half */ | ||
374 | #define maskHF 0 | ||
375 | #define maskLOW (~(~1U << (FIGS - 1))) /* use FIG bits */ | ||
376 | #define shiftFIG (0.5 / (1U << (FIGS - 1))) /* 2^(-FIG) */ | ||
377 | |||
378 | #else /* 32 < FIGS <= 64 */ | ||
379 | |||
380 | /* must take care to not shift stuff by more than 31 slots */ | ||
381 | |||
382 | /* use FIG - 32 bits from higher half */ | ||
383 | #define maskHF (~(~1U << (FIGS - 33))) | ||
384 | |||
385 | /* use all bits from lower half */ | ||
386 | #define maskLOW (~0) | ||
387 | |||
388 | /* 2^(-FIG) == (1 / 2^33) / 2^(FIG-33) */ | ||
389 | #define shiftFIG ((lua_Number)(1.0 / 8589934592.0) / (1U << (FIGS - 33))) | ||
390 | |||
391 | #endif | ||
364 | 392 | ||
365 | #define twoto32 4294967296.0 /* 2^32 */ | 393 | #define twoto32 l_mathop(4294967296.0) /* 2^32 */ |
366 | 394 | ||
367 | static double I2d (I x) { | 395 | static lua_Number I2d (I x) { |
368 | return ((x.x1 & mask21) * twoto32 + (x.x2 & mask32)) * twotomin53; | 396 | return ((x.h & maskHF) * twoto32 + (x.l & maskLOW)) * shiftFIG; |
369 | } | 397 | } |
370 | 398 | ||
371 | static lua_Unsigned I2UInt (I x) { | 399 | static lua_Unsigned I2UInt (I x) { |
372 | return ((lua_Unsigned)x.x1 << 31 << 1) | x.x2; | 400 | return ((lua_Unsigned)x.h << 31 << 1) | x.l; |
373 | } | 401 | } |
374 | 402 | ||
375 | static I Int2I (lua_Integer n) { | 403 | static I Int2I (lua_Integer n) { |
376 | return pack(n, n >> 31 >> 1); | 404 | return pack(n, n >> 31 >> 1); |
377 | } | 405 | } |
378 | 406 | ||
379 | #endif /* } */ | 407 | #endif /* } */ |
380 | 408 | ||
381 | 409 | ||
382 | /* | 410 | /* |
@@ -435,7 +463,7 @@ static int math_random (lua_State *L) { | |||
435 | I rv = xorshift128plus(state->s); /* next pseudo-random value */ | 463 | I rv = xorshift128plus(state->s); /* next pseudo-random value */ |
436 | switch (lua_gettop(L)) { /* check number of arguments */ | 464 | switch (lua_gettop(L)) { /* check number of arguments */ |
437 | case 0: { /* no arguments */ | 465 | case 0: { /* no arguments */ |
438 | lua_pushnumber(L, (lua_Number)I2d(rv)); /* float between 0 and 1 */ | 466 | lua_pushnumber(L, I2d(rv)); /* float between 0 and 1 */ |
439 | return 1; | 467 | return 1; |
440 | } | 468 | } |
441 | case 1: { /* only upper limit */ | 469 | case 1: { /* only upper limit */ |