shithub: femtolisp

Download patch

ref: b09398e98563c23b6988e77b7b5ab84c0e03ceb7
parent: 0f11cb9cc11baa2960aa47eeb5e2d8a28ce271b3
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sat Apr 15 20:08:08 EDT 2023

replace mt19937 with Cocoa with Love modified 64-bit version

--- /dev/null
+++ b/3rd/mt19937-64.c
@@ -1,0 +1,178 @@
+/*
+   A C-program for MT19937-64 (2004/9/29 version).
+   Coded by Takuji Nishimura and Makoto Matsumoto.
+
+   This is a 64-bit version of Mersenne Twister pseudorandom number
+   generator.
+
+   Before using, initialize the state by using init_genrand64(seed)
+   or init_by_array64(init_key, key_length).
+
+   Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura,
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+     1. Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+
+     2. Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+
+     3. The names of its contributors may not be used to endorse or promote
+        products derived from this software without specific prior written
+        permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   References:
+   T. Nishimura, ``Tables of 64-bit Mersenne Twisters''
+     ACM Transactions on Modeling and
+     Computer Simulation 10. (2000) 348--357.
+   M. Matsumoto and T. Nishimura,
+     ``Mersenne Twister: a 623-dimensionally equidistributed
+       uniform pseudorandom number generator''
+     ACM Transactions on Modeling and
+     Computer Simulation 8. (Jan. 1998) 3--30.
+
+   Any feedback is very welcome.
+   http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces)
+*/
+
+#include "mt19937-64.h"
+
+#define NN 312
+#define MM 156
+#define MATRIX_A 0xB5026F5AA96619E9ULL
+#define UM 0xFFFFFFFF80000000ULL /* Most significant 33 bits */
+#define LM 0x7FFFFFFFULL /* Least significant 31 bits */
+
+/* initializes mt[NN] with a seed */
+void
+init_genrand64(mt19937_64 *context, unsigned long long seed)
+{
+	context->mt[0] = seed;
+	for(context->mti=1; context->mti<NN; context->mti++)
+		context->mt[context->mti] =  (6364136223846793005ULL * (context->mt[context->mti-1] ^ (context->mt[context->mti-1] >> 62)) + context->mti);
+}
+
+/* initialize by an array with array-length */
+/* init_key is the array for initializing keys */
+/* key_length is its length */
+void
+init_by_array64(mt19937_64 *context, unsigned long long init_key[], unsigned long long key_length)
+{
+    unsigned long long i, j, k;
+
+    init_genrand64(context, 19650218ULL);
+    i = 1;
+    j = 0;
+    k = NN > key_length ? NN : key_length;
+    for(; k; k--){
+        context->mt[i] = context->mt[i] ^ ((context->mt[i-1] ^ (context->mt[i-1] >> 62)) * 3935559000370003845ULL) + init_key[j] + j; /* non linear */
+        i++;
+        j++;
+        if(i >= NN){
+        	context->mt[0] = context->mt[NN-1];
+        	i = 1;
+        }
+        if(j >= key_length)
+        	j = 0;
+    }
+    for(k = NN-1; k; k--){
+        context->mt[i] = context->mt[i] ^ ((context->mt[i-1] ^ (context->mt[i-1] >> 62)) * 2862933555777941757ULL) - i; /* non linear */
+        i++;
+        if(i >= NN){
+        	context->mt[0] = context->mt[NN-1];
+        	i = 1;
+        }
+    }
+
+    context->mt[0] = 1ULL << 63; /* MSB is 1; assuring non-zero initial array */
+}
+
+/* generates a random number on [0, 2^64-1]-interval */
+unsigned long long
+genrand64_int64(mt19937_64 *context)
+{
+	/* This is the altered Cocoa with Love implementation. */
+	int i, j;
+	unsigned long long result;
+
+	if(context->mti >= NN){ /* generate NN words at one time */
+		int mid = NN / 2;
+		unsigned long long stateMid = context->mt[mid];
+		unsigned long long x;
+		unsigned long long y;
+
+		/* NOTE: this "untwist" code is modified from the original to improve
+		 * performance, as described here:
+		 * http://www.cocoawithlove.com/blog/2016/05/19/random-numbers.html
+		 * These modifications are offered for use under the original icense at
+		 * the top of this file.
+		 */
+		for(i = 0, j = mid; i != mid - 1; i++, j++){
+			x = (context->mt[i] & UM) | (context->mt[i + 1] & LM);
+			context->mt[i] = context->mt[i + mid] ^ (x >> 1) ^ ((context->mt[i + 1] & 1) * MATRIX_A);
+			y = (context->mt[j] & UM) | (context->mt[j + 1] & LM);
+			context->mt[j] = context->mt[j - mid] ^ (y >> 1) ^ ((context->mt[j + 1] & 1) * MATRIX_A);
+		}
+		x = (context->mt[mid - 1] & UM) | (stateMid & LM);
+		context->mt[mid - 1] = context->mt[NN - 1] ^ (x >> 1) ^ ((stateMid & 1) * MATRIX_A);
+		y = (context->mt[NN - 1] & UM) | (context->mt[0] & LM);
+		context->mt[NN - 1] = context->mt[mid - 1] ^ (y >> 1) ^ ((context->mt[0] & 1) * MATRIX_A);
+		context->mti = 0;
+	}
+
+	result = context->mt[context->mti];
+	context->mti = context->mti + 1;
+
+	result ^= (result >> 29) & 0x5555555555555555ULL;
+	result ^= (result << 17) & 0x71D67FFFEDA60000ULL;
+	result ^= (result << 37) & 0xFFF7EEE000000000ULL;
+	result ^= (result >> 43);
+
+	return result;
+}
+
+/* generates a random number on [0, 2^63-1]-interval */
+long long
+genrand64_int63(mt19937_64 *context)
+{
+    return (long long)(genrand64_int64(context) >> 1);
+}
+
+/* generates a random number on [0,1]-real-interval */
+double
+genrand64_real1(mt19937_64 *context)
+{
+    return (genrand64_int64(context) >> 11) * (1.0/9007199254740991.0);
+}
+
+/* generates a random number on [0,1)-real-interval */
+double
+genrand64_real2(mt19937_64 *context)
+{
+    return (genrand64_int64(context) >> 11) * (1.0/9007199254740992.0);
+}
+
+/* generates a random number on (0,1)-real-interval */
+double
+genrand64_real3(mt19937_64 *context)
+{
+	return ((genrand64_int64(context) >> 12) + 0.5) * (1.0/4503599627370496.0);
+}
--- /dev/null
+++ b/3rd/mt19937-64.h
@@ -1,0 +1,14 @@
+typedef struct mt19937_64 mt19937_64;
+
+struct mt19937_64 {
+	unsigned long long mt[312];
+	int mti;
+};
+
+void init_genrand64(mt19937_64 *context, unsigned long long seed);
+void init_by_array64(mt19937_64 *context, unsigned long long init_key[], unsigned long long key_length);
+unsigned long long genrand64_int64(mt19937_64 *context);
+long long genrand64_int63(mt19937_64 *context);
+double genrand64_real1(mt19937_64 *context);
+double genrand64_real2(mt19937_64 *context);
+double genrand64_real3(mt19937_64 *context);
--- a/3rd/mt19937ar.c
+++ /dev/null
@@ -1,171 +1,0 @@
-/*
-   A C-program for MT19937, with initialization improved 2002/1/26.
-   Coded by Takuji Nishimura and Makoto Matsumoto.
-
-   Before using, initialize the state by using init_genrand(seed)
-   or init_by_array(init_key, key_length).
-
-   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
-   All rights reserved.
-
-   Redistribution and use in source and binary forms, with or without
-   modification, are permitted provided that the following conditions
-   are met:
-
-     1. Redistributions of source code must retain the above copyright
-        notice, this list of conditions and the following disclaimer.
-
-     2. Redistributions in binary form must reproduce the above copyright
-        notice, this list of conditions and the following disclaimer in the
-        documentation and/or other materials provided with the distribution.
-
-     3. The names of its contributors may not be used to endorse or promote
-        products derived from this software without specific prior written
-        permission.
-
-   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-   Any feedback is very welcome.
-   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
-   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
-*/
-
-/* Period parameters */
-#define mtN 624
-#define mtM 397
-#define MATRIX_A   0x9908b0dfU /* constant vector a */
-#define UPPER_MASK 0x80000000U /* most significant w-r bits */
-#define LOWER_MASK 0x7fffffffU /* least significant r bits */
-
-static uint32_t mt[mtN]; /* the array for the state vector  */
-static int mti=mtN+1; /* mti==mtN+1 means mt[mtN] is not initialized */
-
-/* initializes mt[mtN] with a seed */
-void init_genrand(uint32_t s)
-{
-    mt[0]= s & 0xffffffffU;
-    for (mti=1; mti<mtN; mti++) {
-        mt[mti] =
-	    (1812433253U * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
-        /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
-        /* In the previous versions, MSBs of the seed affect   */
-        /* only MSBs of the array mt[].                        */
-        /* 2002/01/09 modified by Makoto Matsumoto             */
-        mt[mti] &= 0xffffffffU;
-        /* for >32 bit machines */
-    }
-}
-
-/* initialize by an array with array-length */
-/* init_key is the array for initializing keys */
-/* key_length is its length */
-/* slight change for C++, 2004/2/26 */
-void init_by_array(uint32_t init_key[], int key_length)
-{
-    int i, j, k;
-    init_genrand(19650218U);
-    i=1; j=0;
-    k = (mtN>key_length ? mtN : key_length);
-    for (; k; k--) {
-        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525U))
-          + init_key[j] + j; /* non linear */
-        mt[i] &= 0xffffffffU; /* for WORDSIZE > 32 machines */
-        i++; j++;
-        if (i>=mtN) { mt[0] = mt[mtN-1]; i=1; }
-        if (j>=key_length) j=0;
-    }
-    for (k=mtN-1; k; k--) {
-        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941U))
-          - i; /* non linear */
-        mt[i] &= 0xffffffffU; /* for WORDSIZE > 32 machines */
-        i++;
-        if (i>=mtN) { mt[0] = mt[mtN-1]; i=1; }
-    }
-
-    mt[0] = 0x80000000U; /* MSB is 1; assuring non-zero initial array */
-}
-
-/* generates a random number on [0,0xffffffff]-interval */
-uint32_t genrand_int32(void)
-{
-    uint32_t y;
-    static uint32_t mag01[2]={0x0U, MATRIX_A};
-    /* mag01[x] = x * MATRIX_A  for x=0,1 */
-
-    if (mti >= mtN) { /* generate mtN words at one time */
-        int kk;
-
-        if (mti == mtN+1)   /* if init_genrand() has not been called, */
-            init_genrand(5489U); /* a default initial seed is used */
-
-        for (kk=0;kk<mtN-mtM;kk++) {
-            y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
-            mt[kk] = mt[kk+mtM] ^ (y >> 1) ^ mag01[y & 0x1U];
-        }
-        for (;kk<mtN-1;kk++) {
-            y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
-            mt[kk] = mt[kk+(mtM-mtN)] ^ (y >> 1) ^ mag01[y & 0x1U];
-        }
-        y = (mt[mtN-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
-        mt[mtN-1] = mt[mtM-1] ^ (y >> 1) ^ mag01[y & 0x1U];
-
-        mti = 0;
-    }
-
-    y = mt[mti++];
-
-    /* Tempering */
-    y ^= (y >> 11);
-    y ^= (y << 7) & 0x9d2c5680U;
-    y ^= (y << 15) & 0xefc60000U;
-    y ^= (y >> 18);
-
-    return y;
-}
-
-#if 0
-/* generates a random number on [0,0x7fffffff]-interval */
-long genrand_int31(void)
-{
-    return (long)(genrand_int32()>>1);
-}
-
-/* generates a random number on [0,1]-real-interval */
-double genrand_real1(void)
-{
-    return genrand_int32()*(1.0/4294967295.0);
-    /* divided by 2^32-1 */
-}
-
-/* generates a random number on [0,1)-real-interval */
-double genrand_real2(void)
-{
-    return genrand_int32()*(1.0/4294967296.0);
-    /* divided by 2^32 */
-}
-
-/* generates a random number on (0,1)-real-interval */
-double genrand_real3(void)
-{
-    return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0);
-    /* divided by 2^32 */
-}
-
-/* generates a random number on [0,1) with 53-bit resolution*/
-double genrand_res53(void)
-{
-    uint32_t a=genrand_int32()>>5, b=genrand_int32()>>6;
-    return(a*67108864.0+b)*(1.0/9007199254740992.0);
-}
-#endif
--- a/Makefile
+++ b/Makefile
@@ -54,6 +54,7 @@
 	3rd/mp/u16.o\
 	3rd/mp/u32.o\
 	3rd/mp/u64.o\
+	3rd/mt19937-64.o\
 
 .PHONY: all default test clean
 
--- a/builtins.c
+++ b/builtins.c
@@ -372,11 +372,12 @@
 BUILTIN("rand", rand)
 {
 	USED(args); USED(nargs);
+	uint64_t x = genrand_int63();
 	fixnum_t r;
 #ifdef BITS64
-	r = ((((uint64_t)random())<<32) | random()) & 0x1fffffffffffffffLL;
+	r = x >> 3;
 #else
-	r = random() & 0x1fffffff;
+	r = x >> (32+3);
 #endif
 	return fixnum(r);
 }
@@ -384,31 +385,25 @@
 BUILTIN("rand.uint32", rand_uint32)
 {
 	USED(args); USED(nargs);
-	uint32_t r = random();
-#ifdef BITS64
-	return fixnum(r);
-#else
-	return mk_uint32(r);
-#endif
+	return mk_uint32(genrand_uint32());
 }
 
 BUILTIN("rand.uint64", rand_uint64)
 {
 	USED(args); USED(nargs);
-	uint64_t r = (((uint64_t)random())<<32) | random();
-	return mk_uint64(r);
+	return mk_uint64(genrand_uint64());
 }
 
 BUILTIN("rand.double", rand_double)
 {
 	USED(args); USED(nargs);
-	return mk_double(rand_double());
+	return mk_double(genrand_double());
 }
 
 BUILTIN("rand.float", rand_float)
 {
 	USED(args); USED(nargs);
-	return mk_float(rand_float());
+	return mk_float(genrand_double());
 }
 
 #define BUILTIN_(lname, cname) \
--- a/llt/llt.h
+++ b/llt/llt.h
@@ -81,15 +81,11 @@
 uint32_t memhash32(const char* buf, size_t n);
 
 /* random.c */
-#define random() genrand_int32()
-#define srandom(n) init_genrand(n)
-double rand_double(void);
-float rand_float(void);
-double randn(void);
 void randomize(void);
-uint32_t genrand_int32(void);
-void init_genrand(uint32_t s);
-uint64_t i64time(void);
+double genrand_double(void);
+uint64_t genrand_uint64(void);
+uint32_t genrand_uint32(void);
+int64_t genrand_int63(void);
 
 /* utils.c */
 char *uint2str(char *dest, size_t len, uint64_t num, uint32_t base);
--- a/llt/random.c
+++ b/llt/random.c
@@ -2,58 +2,37 @@
   random numbers
 */
 #include "llt.h"
-#include "ieee754.h"
-#include "mt19937ar.c"
+#include "mt19937-64.h"
 
-double
-rand_double()
-{
-	union ieee754_double d;
+static mt19937_64 ctx;
 
-	d.ieee.mantissa0 = genrand_int32();
-	d.ieee.mantissa1 = genrand_int32();
-	d.ieee.negative = 0;
-	d.ieee.exponent = IEEE754_DOUBLE_BIAS + 0; /* 2^0 */
-	return d.d - 1.0;
+uint64_t
+genrand_uint64(void)
+{
+	return genrand64_int64(&ctx);
 }
 
-float
-rand_float()
+uint32_t
+genrand_uint32(void)
 {
-	union ieee754_float f;
+	return genrand64_int64(&ctx) >> 32;
+}
 
-	f.ieee.mantissa = genrand_int32();
-	f.ieee.negative = 0;
-	f.ieee.exponent = IEEE754_FLOAT_BIAS + 0; /* 2^0 */
-	return f.f - 1.0;
+int64_t
+genrand_int63(void)
+{
+	return genrand64_int63(&ctx);
 }
 
 double
-randn()
+genrand_double(void)
 {
-	double s, vre, vim, ure, uim;
-	static double next = -42;
-
-	if(next != -42){
-		s = next;
-		next = -42;
-		return s;
-	}
-	do{
-		ure = rand_double();
-		uim = rand_double();
-		vre = 2*ure - 1;
-		vim = 2*uim - 1;
-		s = vre*vre + vim*vim;
-	}while(s >= 1);
-	s = sqrt(-2*log(s)/s);
-	next = s * vre;
-	return s * vim;
+	return genrand64_real1(&ctx);
 }
 
 void
 randomize(void)
 {
-	uint64_t tm = i64time();
-	init_by_array((uint32_t*)&tm, 2);
+	unsigned long long tm = i64time();
+	init_by_array64(&ctx, &tm, 1);
 }
--- a/mkfile
+++ b/mkfile
@@ -25,6 +25,7 @@
 	iostream.$O\
 	string.$O\
 	table.$O\
+	3rd/mt19937-64.$O\
 	3rd/wcwidth.$O\
 	llt/bitvector-ops.$O\
 	llt/bitvector.$O\