diff options
author | Warren Weckesser <warren.weckesser@gmail.com> | 2020-04-25 12:28:57 -0400 |
---|---|---|
committer | Warren Weckesser <warren.weckesser@gmail.com> | 2020-04-26 16:43:03 -0400 |
commit | e8b84012463927a1fc9c5a236ce7c4ab4a7effaa (patch) | |
tree | d47cfce8d5719302050ee0eff35670e024c34937 /numpy/random/src | |
parent | 87964f1c5738492b152e80f7e38010c69214e5ae (diff) | |
download | numpy-e8b84012463927a1fc9c5a236ce7c4ab4a7effaa.tar.gz |
BUG: random: Generator.integers(2**32) always returned 0.
When the input to Generator.integers was 2**32, the value 2**32-1
was being passed as the `rng` argument to the 32-bit Lemire method,
but that method requires `rng` be strictly less then 2**32-1.
The fix was to handle 2**32-1 by calling next_uint32 directly.
This also works for the legacy code without changing the stream
of random integers from `randint`.
Closes gh-16066.
Diffstat (limited to 'numpy/random/src')
-rw-r--r-- | numpy/random/src/distributions/distributions.c | 42 |
1 files changed, 31 insertions, 11 deletions
diff --git a/numpy/random/src/distributions/distributions.c b/numpy/random/src/distributions/distributions.c index 0b46dc6d8..d3ea64735 100644 --- a/numpy/random/src/distributions/distributions.c +++ b/numpy/random/src/distributions/distributions.c @@ -1337,6 +1337,14 @@ uint64_t random_bounded_uint64(bitgen_t *bitgen_state, uint64_t off, return off; } else if (rng <= 0xFFFFFFFFUL) { /* Call 32-bit generator if range in 32-bit. */ + if (rng == 0xFFFFFFFFUL) { + /* + * The 32-bit Lemire method does not handle rng=0xFFFFFFFF, so we'll + * call next_uint32 directly. This also works when use_masked is True, + * so we handle both cases here. + */ + return off + (uint64_t) next_uint32(bitgen_state); + } if (use_masked) { return off + buffered_bounded_masked_uint32(bitgen_state, rng, mask, NULL, NULL); @@ -1450,22 +1458,34 @@ void random_bounded_uint64_fill(bitgen_t *bitgen_state, uint64_t off, out[i] = off; } } else if (rng <= 0xFFFFFFFFUL) { - uint32_t buf = 0; - int bcnt = 0; - /* Call 32-bit generator if range in 32-bit. */ - if (use_masked) { - /* Smallest bit mask >= max */ - uint64_t mask = gen_mask(rng); + /* + * The 32-bit Lemire method does not handle rng=0xFFFFFFFF, so we'll + * call next_uint32 directly. This also works when use_masked is True, + * so we handle both cases here. + */ + if (rng == 0xFFFFFFFFUL) { for (i = 0; i < cnt; i++) { - out[i] = off + buffered_bounded_masked_uint32(bitgen_state, rng, mask, - &bcnt, &buf); + out[i] = off + (uint64_t) next_uint32(bitgen_state); } } else { - for (i = 0; i < cnt; i++) { - out[i] = off + - buffered_bounded_lemire_uint32(bitgen_state, rng, &bcnt, &buf); + uint32_t buf = 0; + int bcnt = 0; + + if (use_masked) { + /* Smallest bit mask >= max */ + uint64_t mask = gen_mask(rng); + + for (i = 0; i < cnt; i++) { + out[i] = off + buffered_bounded_masked_uint32(bitgen_state, rng, mask, + &bcnt, &buf); + } + } else { + for (i = 0; i < cnt; i++) { + out[i] = off + + buffered_bounded_lemire_uint32(bitgen_state, rng, &bcnt, &buf); + } } } } else if (rng == 0xFFFFFFFFFFFFFFFFULL) { |