From 6ba36e4f5de082b333d4b3fffd5292a234cdf790 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 23 Jun 2022 12:54:38 +0200 Subject: [PATCH] Improve Math.random randomness. 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". --- jsi.h | 2 +- jsmath.c | 27 +++++++++++---------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/jsi.h b/jsi.h index c9e17fd..e2bca8b 100644 --- a/jsi.h +++ b/jsi.h @@ -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 */ diff --git a/jsmath.c b/jsmath.c index 1998c5d..631d616 100644 --- a/jsmath.c +++ b/jsmath.c @@ -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 -#endif - #include static double jsM_round(double x) @@ -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)