Commits

Amaury Forgeot d'Arc  committed 0ec3d77

Issue1381 resolved: Prevent random.jumpahead() to yield random values above 1.0.

Similar to CPython issue14591, even if we don't use exactly the same algorithm
(The n%i operation operates on C ints, when CPython uses Python numbers)

  • Participants
  • Parent commits 9fe829a

Comments (0)

Files changed (2)

File rpython/rlib/rrandom.py

 
     def jumpahead(self, n):
         mt = self.state
-        for i in range(N - 1, 0, -1):
+        for i in range(N - 1, 1, -1):
             j = n % i
             mt[i], mt[j] = mt[j], mt[i]
-        for i in range(N):
+        nonzero = False
+        for i in range(1, N):
             mt[i] += r_uint(i + 1)
+            mt[i] &= r_uint(0xffffffff)
+            nonzero |= bool(mt[i])
+        # Ensure the state is nonzero: in the unlikely event that mt[1] through
+        # mt[N-1] are all zero, set the MSB of mt[0] (see issue #14591). In the
+        # normal case, we fall back to the pre-issue 14591 behaviour for mt[0].
+        if nonzero:
+            mt[0] += r_uint(1)
+            mt[0] &= r_uint(0xffffffff)
+        else:
+            mt[0] = r_uint(0x80000000)
+        print mt[:3]
         self.index = N

File rpython/rlib/test/test_rrandom.py

     assert tuple(rnd.state) + (rnd.index, ) == cpyrandom.getstate()
 
 
+def test_jumpahead_badstate():
+    rnd = Random()
+    s, j = 4043161618, 2674112291824205302
+    rnd.init_by_array([s])
+    rnd.jumpahead(j)
+    for i in range(500):
+        r = rnd.random()
+        assert r <= 1.0, (r, i)
+
 def test_translate():
     def f(x, y):
         x = r_uint(x)