summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Sheppard <kevin.sheppard@gmail.com>2020-12-04 23:03:23 +0000
committerKevin Sheppard <kevin.k.sheppard@gmail.com>2020-12-11 15:27:13 +0000
commit52ecd5a97ce3ff4dad72935b8bf67ba2cfb6908e (patch)
tree5561b20cf8b0190021275fc395fb52f46d096830
parentba596df4cc23445a117c3785239a75a3cab6b2f2 (diff)
downloadnumpy-52ecd5a97ce3ff4dad72935b8bf67ba2cfb6908e.tar.gz
BUG: Enforce high >= low on uniform number generators
Check that high is weakly larger than low and raise if now closes #17905
-rw-r--r--numpy/random/_generator.pyx15
-rw-r--r--numpy/random/mtrand.pyx15
-rw-r--r--numpy/random/tests/test_generator_mt19937.py6
-rw-r--r--numpy/random/tests/test_random.py6
4 files changed, 28 insertions, 14 deletions
diff --git a/numpy/random/_generator.pyx b/numpy/random/_generator.pyx
index 7ffa36775..cd951526b 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. The default value is 1.0. high - low must be
+ non-negative.
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),
@@ -914,7 +915,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 +924,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 +944,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/mtrand.pyx b/numpy/random/mtrand.pyx
index d43e7f5aa..7f4fe1c3c 100644
--- a/numpy/random/mtrand.pyx
+++ b/numpy/random/mtrand.pyx
@@ -1026,7 +1026,8 @@ cdef class RandomState:
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 or equal to high. The default value is 1.0.
+ less than or equal to high. The default value is 1.0. high - low must be
+ non-negative.
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),
@@ -1095,7 +1096,7 @@ cdef class RandomState:
"""
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)
@@ -1104,13 +1105,13 @@ cdef class RandomState:
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)
@@ -1123,7 +1124,7 @@ cdef class RandomState:
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..4b534fcec 100644
--- a/numpy/random/tests/test_generator_mt19937.py
+++ b/numpy/random/tests/test_generator_mt19937.py
@@ -1666,6 +1666,12 @@ class TestRandomDist:
# DBL_MAX by increasing fmin a bit
random.uniform(low=np.nextafter(fmin, 1), high=fmax / 1e17)
+ 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
diff --git a/numpy/random/tests/test_random.py b/numpy/random/tests/test_random.py
index c13fc39e3..473ca08e4 100644
--- a/numpy/random/tests/test_random.py
+++ b/numpy/random/tests/test_random.py
@@ -916,6 +916,12 @@ class TestRandomDist:
# account for i386 extended precision DBL_MAX / 1e17 + DBL_MAX >
# DBL_MAX by increasing fmin a bit
np.random.uniform(low=np.nextafter(fmin, 1), high=fmax / 1e17)
+
+ def test_uniform_neg_range(self):
+ func = np.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