summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2021-11-12 12:47:48 -0600
committerGitHub <noreply@github.com>2021-11-12 12:47:48 -0600
commit1995e2cdfd17ec75e37cc6e69a42ce9000aac966 (patch)
tree2fd5e74577d67e035dac297cf69fa518438a657d /numpy
parent9c28152850109cdb567eaab7a872aa1429e51f55 (diff)
parente5af24d51a4835f2a32220f8d7a5e673fd2638b1 (diff)
downloadnumpy-1995e2cdfd17ec75e37cc6e69a42ce9000aac966.tar.gz
Merge pull request #20314 from WarrenWeckesser/float32-rand-unused-bit
BUG: Get full precision for 32 bit floating point random values.
Diffstat (limited to 'numpy')
-rw-r--r--numpy/random/src/distributions/distributions.c2
-rw-r--r--numpy/random/tests/test_direct.py13
-rw-r--r--numpy/random/tests/test_generator_mt19937.py12
3 files changed, 21 insertions, 6 deletions
diff --git a/numpy/random/src/distributions/distributions.c b/numpy/random/src/distributions/distributions.c
index adf4db4a7..bd1e1faa4 100644
--- a/numpy/random/src/distributions/distributions.c
+++ b/numpy/random/src/distributions/distributions.c
@@ -17,7 +17,7 @@ static NPY_INLINE uint64_t next_uint64(bitgen_t *bitgen_state) {
}
static NPY_INLINE float next_float(bitgen_t *bitgen_state) {
- return (next_uint32(bitgen_state) >> 9) * (1.0f / 8388608.0f);
+ return (next_uint32(bitgen_state) >> 8) * (1.0f / 16777216.0f);
}
/* Random generators for external use */
diff --git a/numpy/random/tests/test_direct.py b/numpy/random/tests/test_direct.py
index ea1ebacb6..58d966adf 100644
--- a/numpy/random/tests/test_direct.py
+++ b/numpy/random/tests/test_direct.py
@@ -46,25 +46,27 @@ def assert_state_equal(actual, target):
assert actual[key] == target[key]
+def uint32_to_float32(u):
+ return ((u >> np.uint32(8)) * (1.0 / 2**24)).astype(np.float32)
+
+
def uniform32_from_uint64(x):
x = np.uint64(x)
upper = np.array(x >> np.uint64(32), dtype=np.uint32)
lower = np.uint64(0xffffffff)
lower = np.array(x & lower, dtype=np.uint32)
joined = np.column_stack([lower, upper]).ravel()
- out = (joined >> np.uint32(9)) * (1.0 / 2 ** 23)
- return out.astype(np.float32)
+ return uint32_to_float32(joined)
def uniform32_from_uint53(x):
x = np.uint64(x) >> np.uint64(16)
x = np.uint32(x & np.uint64(0xffffffff))
- out = (x >> np.uint32(9)) * (1.0 / 2 ** 23)
- return out.astype(np.float32)
+ return uint32_to_float32(x)
def uniform32_from_uint32(x):
- return (x >> np.uint32(9)) * (1.0 / 2 ** 23)
+ return uint32_to_float32(x)
def uniform32_from_uint(x, bits):
@@ -126,6 +128,7 @@ def gauss_from_uint(x, n, bits):
return gauss[:n]
+
def test_seedsequence():
from numpy.random.bit_generator import (ISeedSequence,
ISpawnableSeedSequence,
diff --git a/numpy/random/tests/test_generator_mt19937.py b/numpy/random/tests/test_generator_mt19937.py
index 7ddccaf86..d057122f1 100644
--- a/numpy/random/tests/test_generator_mt19937.py
+++ b/numpy/random/tests/test_generator_mt19937.py
@@ -774,6 +774,18 @@ class TestRandomDist:
desired = 0.0969992
assert_array_almost_equal(actual, desired, decimal=7)
+ @pytest.mark.parametrize('dtype, uint_view_type',
+ [(np.float32, np.uint32),
+ (np.float64, np.uint64)])
+ def test_random_distribution_of_lsb(self, dtype, uint_view_type):
+ random = Generator(MT19937(self.seed))
+ sample = random.random(100000, dtype=dtype)
+ num_ones_in_lsb = np.count_nonzero(sample.view(uint_view_type) & 1)
+ # The probability of a 1 in the least significant bit is 0.25.
+ # With a sample size of 100000, the probability that num_ones_in_lsb
+ # is outside the following range is less than 5e-11.
+ assert 24100 < num_ones_in_lsb < 25900
+
def test_random_unsupported_type(self):
assert_raises(TypeError, random.random, dtype='int32')