ref: 3bd234c685180c507e4eb40b1ad3689d4b9188ce
parent: fe8cac61e3bf64900e6f608d05e0c4d0f9b4af5e
author: Tor Andersson <tor.andersson@artifex.com>
date: Sun Oct 24 09:12:07 EDT 2021
Math.random: Use Lehmer LCG instead of borrowing the hack from musl. For simplicity of implementation, use the minimal standard generator described in "Random Number Generators: Good ones are hard to find" by Park & Miller (ACM 1988, Volume 31, Number 10).
--- a/jsmath.c
+++ b/jsmath.c
@@ -2,24 +2,15 @@
#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>
-#define JS_RAND_MAX (0x7fffffff)
-
-static unsigned int jsM_rand_temper(unsigned int x)
-{
- x ^= x>>11;
- x ^= x<<7 & 0x9D2C5680;
- x ^= x<<15 & 0xEFC60000;
- x ^= x>>18;
- return x;
-}
-
-static int jsM_rand_r(unsigned int *seed)
-{
- return jsM_rand_temper(*seed = *seed * 1103515245 + 12345)/2;
-}
-
static double jsM_round(double x)
{
if (isnan(x)) return x;
@@ -94,9 +85,23 @@
static void Math_random(js_State *J)
{
- js_pushnumber(J, jsM_rand_r(&J->seed) / (JS_RAND_MAX + 1.0));
+ /* 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);
}
+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;
+}
+
static void Math_round(js_State *J)
{
double x = js_tonumber(J, 1);
@@ -156,8 +161,7 @@
void jsB_initmath(js_State *J)
{
- J->seed = time(NULL);
-
+ Math_init_random(J);
js_pushobject(J, jsV_newobject(J, JS_CMATH, J->Object_prototype));
{
jsB_propn(J, "E", 2.7182818284590452354);