summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release/1.9.0-notes.rst8
-rw-r--r--numpy/random/mtrand/mtrand.pyx11
-rw-r--r--numpy/random/mtrand/numpy.pxd2
-rw-r--r--numpy/random/tests/test_random.py29
4 files changed, 48 insertions, 2 deletions
diff --git a/doc/release/1.9.0-notes.rst b/doc/release/1.9.0-notes.rst
index c856904af..9aa39342a 100644
--- a/doc/release/1.9.0-notes.rst
+++ b/doc/release/1.9.0-notes.rst
@@ -112,6 +112,14 @@ performed, and hence the sequence location will be different after a
call to distribution.c::rk_binomial_btpe. Any tests which rely on the RNG
being in a known state should be checked and/or updated as a result.
+Random seed enforced to be a 32 bit unsigned integer
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+``np.random.seed`` and ``np.random.RandomState`` now throw a ``ValueError``
+if the seed cannot safely be converted to 32 bit unsigned integers.
+Applications that now fail can be fixed by masking the higher 32 bit values to
+zero: ``seed = seed & 0xFFFFFFFF``. This is what is done silently in older
+versions so the random stream remains the same.
+
New Features
============
diff --git a/numpy/random/mtrand/mtrand.pyx b/numpy/random/mtrand/mtrand.pyx
index 3f9dcb687..c2603543d 100644
--- a/numpy/random/mtrand/mtrand.pyx
+++ b/numpy/random/mtrand/mtrand.pyx
@@ -628,6 +628,7 @@ cdef class RandomState:
----------
seed : int or array_like, optional
Seed for `RandomState`.
+ Must be convertable to 32 bit unsigned integers.
See Also
--------
@@ -640,9 +641,15 @@ cdef class RandomState:
if seed is None:
errcode = rk_randomseed(self.internal_state)
else:
- rk_seed(operator.index(seed), self.internal_state)
+ idx = operator.index(seed)
+ if idx > int(2**32 - 1) or idx < 0:
+ raise ValueError("Seed must be between 0 and 4294967295")
+ rk_seed(idx, self.internal_state)
except TypeError:
- obj = <ndarray>PyArray_ContiguousFromObject(seed, NPY_LONG, 1, 1)
+ obj = np.asarray(seed).astype(np.int64, casting='safe')
+ if ((obj > int(2**32 - 1)) | (obj < 0)).any():
+ raise ValueError("Seed must be between 0 and 4294967295")
+ obj = obj.astype('L', casting='unsafe')
init_by_array(self.internal_state, <unsigned long *>PyArray_DATA(obj),
PyArray_DIM(obj, 0))
diff --git a/numpy/random/mtrand/numpy.pxd b/numpy/random/mtrand/numpy.pxd
index 6812cc164..c54f79c0a 100644
--- a/numpy/random/mtrand/numpy.pxd
+++ b/numpy/random/mtrand/numpy.pxd
@@ -121,6 +121,8 @@ cdef extern from "numpy/arrayobject.h":
object PyArray_IterNew(object arr)
void PyArray_ITER_NEXT(flatiter it) nogil
+ dtype PyArray_DescrFromType(int)
+
void import_array()
# include functions that were once macros in the new api
diff --git a/numpy/random/tests/test_random.py b/numpy/random/tests/test_random.py
index b6c4fe3af..ef4e7b127 100644
--- a/numpy/random/tests/test_random.py
+++ b/numpy/random/tests/test_random.py
@@ -7,6 +7,35 @@ from numpy.testing import (
from numpy import random
from numpy.compat import asbytes
+class TestSeed(TestCase):
+ def test_scalar(self):
+ s = np.random.RandomState(0)
+ assert_equal(s.randint(1000), 684)
+ s = np.random.RandomState(4294967295)
+ assert_equal(s.randint(1000), 419)
+
+ def test_array(self):
+ s = np.random.RandomState(range(10))
+ assert_equal(s.randint(1000), 468)
+ s = np.random.RandomState(np.arange(10))
+ assert_equal(s.randint(1000), 468)
+ s = np.random.RandomState([0])
+ assert_equal(s.randint(1000), 973)
+ s = np.random.RandomState([4294967295])
+ assert_equal(s.randint(1000), 265)
+
+ def test_invalid_scalar(self):
+ # seed must be a unsigned 32 bit integers
+ assert_raises(TypeError, np.random.RandomState, -0.5)
+ assert_raises(ValueError, np.random.RandomState, -1)
+
+ def test_invalid_array(self):
+ # seed must be a unsigned 32 bit integers
+ assert_raises(TypeError, np.random.RandomState, [-0.5])
+ assert_raises(ValueError, np.random.RandomState, [-1])
+ assert_raises(ValueError, np.random.RandomState, [4294967296])
+ assert_raises(ValueError, np.random.RandomState, [1, 2, 4294967296])
+ assert_raises(ValueError, np.random.RandomState, [1, -2, 4294967296])
class TestBinomial(TestCase):
def test_n_zero(self):