summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatti Picus <matti.picus@gmail.com>2020-12-14 15:49:47 +0200
committerGitHub <noreply@github.com>2020-12-14 15:49:47 +0200
commite4feb7027e397925d220a10dd58b581b87ca1fec (patch)
treef8d7f9528c4e50b892800f280623b34adb18a4d2
parent30114c3b34feef351143fd4676839eaab93af931 (diff)
parenta3bb19df580454a6b98c34e29a00c271c2e411af (diff)
downloadnumpy-e4feb7027e397925d220a10dd58b581b87ca1fec.tar.gz
Merge pull request #17921 from bashtage/uniform-high-low-check
BUG: Enforce high >= low on uniform number generators
-rw-r--r--doc/release/upcoming_changes/17921.compatibility.rst6
-rw-r--r--numpy/random/_generator.pyx19
-rw-r--r--numpy/random/tests/test_generator_mt19937.py15
3 files changed, 29 insertions, 11 deletions
diff --git a/doc/release/upcoming_changes/17921.compatibility.rst b/doc/release/upcoming_changes/17921.compatibility.rst
new file mode 100644
index 000000000..a1e2fb2d0
--- /dev/null
+++ b/doc/release/upcoming_changes/17921.compatibility.rst
@@ -0,0 +1,6 @@
+Validate input values in ``Generator.uniform``
+----------------------------------------------
+Checked that ``high - low >= 0`` in ``np.random.Generator.uniform``. Raises
+``ValueError`` if ``low > high``. Previously out-of-order inputs were accepted
+and silently swapped, so that if ``low > high``, the value generated was
+``high + (low - high) * random()``.
diff --git a/numpy/random/_generator.pyx b/numpy/random/_generator.pyx
index 7ffa36775..e00bc4d98 100644
--- a/numpy/random/_generator.pyx
+++ b/numpy/random/_generator.pyx
@@ -859,7 +859,8 @@ cdef class Generator:
greater than or equal to low. The default value is 0.
high : float or array_like of floats
Upper boundary of the output interval. All values generated will be
- less than high. The default value is 1.0.
+ less than high. high - low must be non-negative. The default value
+ is 1.0.
size : int or tuple of ints, optional
Output shape. If the given shape is, e.g., ``(m, n, k)``, then
``m * n * k`` samples are drawn. If size is ``None`` (default),
@@ -885,10 +886,6 @@ cdef class Generator:
anywhere within the interval ``[a, b)``, and zero elsewhere.
When ``high`` == ``low``, values of ``low`` will be returned.
- If ``high`` < ``low``, the results are officially undefined
- and may eventually raise an error, i.e. do not rely on this
- function to behave when passed arguments satisfying that
- inequality condition.
Examples
--------
@@ -914,7 +911,7 @@ cdef class Generator:
"""
cdef bint is_scalar = True
cdef np.ndarray alow, ahigh, arange
- cdef double _low, _high, range
+ cdef double _low, _high, rng
cdef object temp
alow = <np.ndarray>np.PyArray_FROM_OTF(low, np.NPY_DOUBLE, np.NPY_ALIGNED)
@@ -923,13 +920,13 @@ cdef class Generator:
if np.PyArray_NDIM(alow) == np.PyArray_NDIM(ahigh) == 0:
_low = PyFloat_AsDouble(low)
_high = PyFloat_AsDouble(high)
- range = _high - _low
- if not np.isfinite(range):
- raise OverflowError('Range exceeds valid bounds')
+ rng = _high - _low
+ if not np.isfinite(rng):
+ raise OverflowError('high - low range exceeds valid bounds')
return cont(&random_uniform, &self._bitgen, size, self.lock, 2,
_low, '', CONS_NONE,
- range, '', CONS_NONE,
+ rng, 'high - low', CONS_NON_NEGATIVE,
0.0, '', CONS_NONE,
None)
@@ -943,7 +940,7 @@ cdef class Generator:
raise OverflowError('Range exceeds valid bounds')
return cont(&random_uniform, &self._bitgen, size, self.lock, 2,
alow, '', CONS_NONE,
- arange, '', CONS_NONE,
+ arange, 'high - low', CONS_NON_NEGATIVE,
0.0, '', CONS_NONE,
None)
diff --git a/numpy/random/tests/test_generator_mt19937.py b/numpy/random/tests/test_generator_mt19937.py
index b69cd38d4..c4fb5883c 100644
--- a/numpy/random/tests/test_generator_mt19937.py
+++ b/numpy/random/tests/test_generator_mt19937.py
@@ -1666,6 +1666,21 @@ class TestRandomDist:
# DBL_MAX by increasing fmin a bit
random.uniform(low=np.nextafter(fmin, 1), high=fmax / 1e17)
+ def test_uniform_zero_range(self):
+ func = random.uniform
+ result = func(1.5, 1.5)
+ assert_allclose(result, 1.5)
+ result = func([0.0, np.pi], [0.0, np.pi])
+ assert_allclose(result, [0.0, np.pi])
+ result = func([[2145.12], [2145.12]], [2145.12, 2145.12])
+ assert_allclose(result, 2145.12 + np.zeros((2, 2)))
+
+ def test_uniform_neg_range(self):
+ func = random.uniform
+ assert_raises(ValueError, func, 2, 1)
+ assert_raises(ValueError, func, [1, 2], [1, 1])
+ assert_raises(ValueError, func, [[0, 1],[2, 3]], 2)
+
def test_scalar_exception_propagation(self):
# Tests that exceptions are correctly propagated in distributions
# when called with objects that throw exceptions when converted to