summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Kern <robert.kern@gmail.com>2019-06-28 17:30:33 -0700
committerMatti Picus <matti.picus@gmail.com>2019-06-28 17:30:33 -0700
commite7383b5d5dff636ed92667a28751ce18f7086097 (patch)
treeb4028266c847b8f06a30b090d07033954258a9fd
parentad84b69bda8eb5e2998370148b9e830d40099d5c (diff)
downloadnumpy-e7383b5d5dff636ed92667a28751ce18f7086097.tar.gz
BUG: Ensure consistent interpretation of uint64 states. (#13861)
* BUG: test, fix for big-endian systems
-rw-r--r--numpy/random/bit_generator.pyx4
-rw-r--r--numpy/random/generator.pyx4
-rw-r--r--numpy/random/mtrand.pyx5
-rw-r--r--numpy/random/tests/test_seed_sequence.py16
4 files changed, 25 insertions, 4 deletions
diff --git a/numpy/random/bit_generator.pyx b/numpy/random/bit_generator.pyx
index cd1b628eb..6694e5e4d 100644
--- a/numpy/random/bit_generator.pyx
+++ b/numpy/random/bit_generator.pyx
@@ -438,7 +438,9 @@ cdef class SeedSequence():
data_val ^= data_val >> XSHIFT
state[i_dst] = data_val
if out_dtype == np.dtype(np.uint64):
- state = state.view(np.uint64)
+ # For consistency across different endiannesses, view first as
+ # little-endian then convert the values to the native endianness.
+ state = state.astype('<u4').view('<u8').astype(np.uint64)
return state
def spawn(self, n_children):
diff --git a/numpy/random/generator.pyx b/numpy/random/generator.pyx
index e6b70f176..0e51f411e 100644
--- a/numpy/random/generator.pyx
+++ b/numpy/random/generator.pyx
@@ -498,8 +498,10 @@ cdef class Generator:
"""
cdef Py_ssize_t n_uint32 = ((length - 1) // 4 + 1)
+ # Interpret the uint32s as little-endian to convert them to bytes
+ # consistently.
return self.integers(0, 4294967296, size=n_uint32,
- dtype=np.uint32).tobytes()[:length]
+ dtype=np.uint32).astype('<u4').tobytes()[:length]
def randint(self, low, high=None, size=None, dtype=np.int64, endpoint=False):
"""
diff --git a/numpy/random/mtrand.pyx b/numpy/random/mtrand.pyx
index 5d34368a6..46b6b3388 100644
--- a/numpy/random/mtrand.pyx
+++ b/numpy/random/mtrand.pyx
@@ -671,7 +671,10 @@ cdef class RandomState:
"""
cdef Py_ssize_t n_uint32 = ((length - 1) // 4 + 1)
- return self.randint(0, 4294967296, size=n_uint32, dtype=np.uint32).tobytes()[:length]
+ # Interpret the uint32s as little-endian to convert them to bytes
+ # consistently.
+ return self.randint(0, 4294967296, size=n_uint32,
+ dtype=np.uint32).astype('<u4').tobytes()[:length]
@cython.wraparound(True)
def choice(self, a, size=None, replace=True, p=None):
diff --git a/numpy/random/tests/test_seed_sequence.py b/numpy/random/tests/test_seed_sequence.py
index 34278375a..8d6d604a2 100644
--- a/numpy/random/tests/test_seed_sequence.py
+++ b/numpy/random/tests/test_seed_sequence.py
@@ -33,8 +33,22 @@ def test_reference_data():
[3978441347, 432478529, 3223635119, 138903045],
[296367413, 4262059219, 13109864, 3283683422],
]
- for seed, expected in zip(inputs, outputs):
+ outputs64 = [
+ [2477551240072187391, 9577394838764454085],
+ [15854241394484835714, 11398914698975566411],
+ [13708282465491374871, 16007308345579681096],
+ [15424829579845884309, 1898028439751125927],
+ [9411697742461147792, 15714068361935982142],
+ [10079222287618677782, 12870437757549876199],
+ [17326737873898640088, 729039288628699544],
+ [16644868984619524261, 1544825456798124994],
+ [1857481142255628931, 596584038813451439],
+ [18305404959516669237, 14103312907920476776],
+ ]
+ for seed, expected, expected64 in zip(inputs, outputs, outputs64):
expected = np.array(expected, dtype=np.uint32)
ss = SeedSequence(seed)
state = ss.generate_state(len(expected))
assert_array_equal(state, expected)
+ state64 = ss.generate_state(len(expected64), dtype=np.uint64)
+ assert_array_equal(state64, expected64)