Skip to content

Commit

Permalink
Improve Math.random randomness.
Browse files Browse the repository at this point in the history
Largest possible MLCG that only uses integer arithmetic with doubles.

Parameters from Pierre l'Ecuyers paper "Tables of linear congruential
generators of different sizes and good lattice structure".
  • Loading branch information
ccxvii committed Aug 5, 2022
1 parent 1cbf19e commit 6ba36e4
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 17 deletions.
2 changes: 1 addition & 1 deletion jsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ struct js_State
js_Object *TypeError_prototype;
js_Object *URIError_prototype;

unsigned int seed; /* Math.random seed */
double seed; /* Math.random seed */

int nextref; /* for js_ref use */
js_Object *R; /* registry of hidden values */
Expand Down
27 changes: 11 additions & 16 deletions jsmath.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@
#include "jsvalue.h"
#include "jsbuiltin.h"

#if defined(_MSC_VER) && (_MSC_VER < 1700) /* VS2012 has stdint.h */
typedef unsigned int uint32_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif

#include <time.h>

static double jsM_round(double x)
Expand Down Expand Up @@ -85,21 +78,23 @@ static void Math_pow(js_State *J)

static void Math_random(js_State *J)
{
/* Lehmer generator with a=48271 and m=2^31-1 */
/* Park & Miller (1988). Random Number Generators: Good ones are hard to find. */
J->seed = (uint64_t) J->seed * 48271 % 0x7fffffff;
js_pushnumber(J, (double) J->seed / 0x7fffffff);
// A Lehmer (MLCG) RNG using doubles.
// Parameters from Pierre l'Ecuyer's paper:
// https://www.ams.org/journals/mcom/1999-68-225/S0025-5718-99-00996-5/S0025-5718-99-00996-5.pdf
// m = 2^35 - 31
J->seed = J->seed * fmod(200105.0, 34359738337.0);
js_pushnumber(J, J->seed / 34359738337.0);
}

static void Math_init_random(js_State *J)
{
/* Pick initial seed by scrambling current time with Xorshift. */
/* Marsaglia (2003). Xorshift RNGs. */
J->seed = time(0) + 123;
J->seed ^= J->seed << 13;
J->seed ^= J->seed >> 17;
J->seed ^= J->seed << 5;
J->seed %= 0x7fffffff;
unsigned int seed = time(0) + 123;
seed ^= seed << 13;
seed ^= seed >> 17;
seed ^= seed << 5;
J->seed = seed;
}

static void Math_round(js_State *J)
Expand Down

0 comments on commit 6ba36e4

Please sign in to comment.