blob: 99e4223c541030670666243d2adf134340fc91ed [file] [log] [blame]
/*
* A tiny random number generator.
*
* Currently used for Math.random().
*
* http://www.woodmann.com/forum/archive/index.php/t-3100.html
*/
#include "duk_internal.h"
#define DUK__UPDATE_RND(rnd) do { \
(rnd) += ((rnd) * (rnd)) | 0x05; \
(rnd) = ((rnd) & 0xffffffffU); /* if duk_uint32_t is exactly 32 bits, this is a NOP */ \
} while (0)
#define DUK__RND_BIT(rnd) ((rnd) >> 31) /* only use the highest bit */
DUK_INTERNAL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n) {
duk_small_int_t i;
duk_uint32_t res = 0;
duk_uint32_t rnd;
rnd = thr->heap->rnd_state;
for (i = 0; i < n; i++) {
DUK__UPDATE_RND(rnd);
res <<= 1;
res += DUK__RND_BIT(rnd);
}
thr->heap->rnd_state = rnd;
return res;
}
DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
duk_double_t t;
duk_small_int_t n;
duk_uint32_t rnd;
/*
* XXX: could make this a lot faster if we create the double memory
* representation directly. Feasible easily (must be uniform random).
*/
rnd = thr->heap->rnd_state;
n = 53; /* enough to cover the whole mantissa */
t = 0.0;
do {
DUK__UPDATE_RND(rnd);
t += DUK__RND_BIT(rnd);
t /= 2.0;
} while (--n);
thr->heap->rnd_state = rnd;
DUK_ASSERT(t >= (duk_double_t) 0.0);
DUK_ASSERT(t < (duk_double_t) 1.0);
return t;
}