[pypy-svn] r32414 - in pypy/dist/pypy/module/_random: . test

cfbolz at codespeak.net cfbolz at codespeak.net
Sun Sep 17 16:00:31 CEST 2006


Author: cfbolz
Date: Sun Sep 17 16:00:29 2006
New Revision: 32414

Added:
   pypy/dist/pypy/module/_random/rpy_random.py
   pypy/dist/pypy/module/_random/test/test_mersenne.py
Log:
first steps in rewriting the mersenne twister algorithm in RPython. Basic
generation works, some helpers missing.


Added: pypy/dist/pypy/module/_random/rpy_random.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/_random/rpy_random.py	Sun Sep 17 16:00:29 2006
@@ -0,0 +1,111 @@
+# this code is a version of the mersenne twister random number generator which
+# is supposed to be used from RPython without the Python interpreter wrapping
+# machinery etc.
+
+# this is stolen from CPython's _randommodule.c
+
+from pypy.rpython.rarithmetic import r_uint
+
+N = 624
+M = 397
+MATRIX_A = r_uint(0x9908b0df) # constant vector a
+UPPER_MASK  = r_uint(0x80000000) # most significant w-r bits
+LOWER_MASK = r_uint(0x7fffffff) # least significant r bits
+
+class Random(object):
+    def __init__(self, seed=r_uint(0)):
+        self.state = [r_uint(0)] * N
+        self.index = 0
+        if seed:
+            self.init_genrand(seed)
+
+    def init_genrand(self, s):
+        mt = self.state
+        mt[0]= s & r_uint(0xffffffff)
+        for mti in range(1, N):
+            mt[mti] = (r_uint(1812433253) *
+                           (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[].
+            # for >32 bit machines 
+            mt[mti] &= r_uint(0xffffffff);
+        self.index = mti + 1
+
+    def init_by_array(self, init_key):
+        key_length = len(init_key)
+        mt = self.state
+        self.init_genrand(r_uint(19650218))
+        i = 1
+        j = 0
+        if N > key_length:
+            max_k = N
+        else:
+            max_k = key_length
+        for k in range(max_k, 0, -1):
+            mt[i] = ((mt[i] ^
+                         ((mt[i - 1] ^ (mt[i - 1] >> 30)) * r_uint(1664525)))
+                     + init_key[j] + j) # non linear
+            mt[i] &= r_uint(0xffffffff) # for WORDSIZE > 32 machines
+            i += 1
+            j += 1
+            if i >= N:
+                mt[0] = mt[N - 1]
+                i = 1
+            if j >= key_length:
+                j = 0
+        for k in range(N - 1, 0, -1):
+            mt[i] = ((mt[i] ^
+                        ((mt[i - 1] ^ (mt[i - 1] >> 30)) * r_uint(1566083941)))
+                     - i) # non linear
+            mt[i] &= r_uint(0xffffffff) # for WORDSIZE > 32 machines
+            i += 1
+            if (i>=N):
+                mt[0] = mt[N - 1]
+                i = 1
+        mt[0] = r_uint(0x80000000)
+
+    def genrand32(self):
+        mag01 = [0, MATRIX_A]
+        mt = self.state
+        if self.index >= N:
+            for kk in range(N - M):
+                y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK)
+                mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & r_uint(1)]
+            for kk in range(N - M, N - 1):
+                y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK)
+                mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & r_uint(1)]
+            y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK)
+            mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & r_uint(1)]
+            self.index = 0
+        y = mt[self.index]
+        self.index += 1
+        y ^= y >> 11
+        y ^= (y << 7) & r_uint(0x9d2c5680)
+        y ^= (y << 15) & r_uint(0xefc60000)
+        y ^= (y >> 18)
+        return y
+
+    def random(self):
+        a = self.genrand32() >> 5
+        b = self.genrand32() >> 6
+        return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0)
+
+def main():
+    import sys
+    rnd = Random()
+    rnd.init_genrand(1000)
+    print rnd.index
+
+#    for j in range(100):
+#        print rnd.state[j],
+#        if j % 7 == 6:
+#            print
+#    print "\n"
+    for j in range(5):
+        print rnd.genrand32(),
+        if j % 7 == 6:
+            print
+    print
+
+main()

Added: pypy/dist/pypy/module/_random/test/test_mersenne.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/_random/test/test_mersenne.py	Sun Sep 17 16:00:29 2006
@@ -0,0 +1,17 @@
+from pypy.module._random.rpy_random import Random
+
+# the numbers were created by using CPython's _randommodule.c
+
+def test_init_from_seed():
+    rnd = Random(1000)
+    assert rnd.state[:14] == [1000, 4252021385, 1724402292, 571538732,
+            73690720, 4283493349, 2222270404, 2464917285, 427676011,
+            1101193792, 2887716015, 3670250828, 1664757559, 1538426459]
+
+def test_numbers():
+    rnd = Random(1000)
+    nums = [rnd.genrand32() for i in range(14)]
+    assert nums == [2807145907, 882709079, 493951047, 2621574848, 4081433851,
+            44058974, 2070996316, 1549632257, 3747249597, 3650674304,
+            911961945, 58396205, 174846504, 1478498153]
+



More information about the Pypy-commit mailing list