summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/npymath/npy_math_internal.h.src24
-rw-r--r--numpy/core/tests/test_umath.py79
2 files changed, 77 insertions, 26 deletions
diff --git a/numpy/core/src/npymath/npy_math_internal.h.src b/numpy/core/src/npymath/npy_math_internal.h.src
index 02a37e711..739764398 100644
--- a/numpy/core/src/npymath/npy_math_internal.h.src
+++ b/numpy/core/src/npymath/npy_math_internal.h.src
@@ -420,11 +420,14 @@ NPY_INPLACE @type@ npy_@kind@@c@(@type@ x, @type@ y)
#undef @kind@@c@
#endif
#ifndef HAVE_MODF@C@
-NPY_INPLACE @type@ npy_@kind@@c@(@type@ x, @type@ y)
+NPY_INPLACE @type@
+npy_@kind@@c@(@type@ x, @type@ y)
{
int are_inputs_inf = (npy_isinf(x) && npy_isinf(y));
if (are_inputs_inf || !y) {
- npy_set_floatstatus_invalid();
+ if (!npy_isnan(x)) {
+ npy_set_floatstatus_invalid();
+ }
}
return (@type@) npy_@kind@((double)x, (double) y);
}
@@ -508,11 +511,14 @@ NPY_INPLACE @type@ npy_@kind@@c@(@type@ x, @type@ y)
* #KIND = FMOD#
*/
#ifdef HAVE_FMOD@C@
-NPY_INPLACE @type@ npy_@kind@@c@(@type@ x, @type@ y)
+NPY_INPLACE @type@
+npy_@kind@@c@(@type@ x, @type@ y)
{
int are_inputs_inf = (npy_isinf(x) && npy_isinf(y));
if (are_inputs_inf || !y) {
- npy_set_floatstatus_invalid();
+ if (!npy_isnan(x)) {
+ npy_set_floatstatus_invalid();
+ }
}
return @kind@@c@(x, y);
}
@@ -669,7 +675,9 @@ npy_remainder@c@(@type@ a, @type@ b)
@type@ mod;
if (!b) {
mod = npy_fmod@c@(a, b);
- npy_set_floatstatus_invalid();
+ if (!npy_isnan(a)) {
+ npy_set_floatstatus_invalid();
+ }
} else {
npy_divmod@c@(a, b, &mod);
}
@@ -679,11 +687,11 @@ npy_remainder@c@(@type@ a, @type@ b)
NPY_INPLACE @type@
npy_floor_divide@c@(@type@ a, @type@ b) {
@type@ div, mod;
- if (!b) {
+ if (NPY_UNLIKELY(!b)) {
div = a / b;
if (!a) {
npy_set_floatstatus_invalid();
- } else {
+ } else if (!npy_isnan(a)) {
npy_set_floatstatus_divbyzero();
}
} else {
@@ -705,7 +713,7 @@ npy_divmod@c@(@type@ a, @type@ b, @type@ *modulus)
mod = npy_fmod@c@(a, b);
if (!b) {
div = a / b;
- if (a) {
+ if (a && !npy_isnan(a)) {
npy_set_floatstatus_divbyzero();
}
/* If b == 0, return result of fmod. For IEEE is nan */
diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py
index 2ee97ebb8..d3dbedf98 100644
--- a/numpy/core/tests/test_umath.py
+++ b/numpy/core/tests/test_umath.py
@@ -298,6 +298,16 @@ class TestDivision:
# test corner cases like 1.0//0.0 for errors and return vals
x = np.zeros(10, dtype=dtype)
y = np.ones(10, dtype=dtype)
+ fnan = np.array(np.nan, dtype=dtype)
+ fone = np.array(1.0, dtype=dtype)
+ fzer = np.array(0.0, dtype=dtype)
+ finf = np.array(np.inf, dtype=dtype)
+ div = np.floor_divide(fnan, fone)
+ assert(np.isnan(div)), "dt: %s, div: %s" % (dt, div)
+ div = np.floor_divide(fone, fnan)
+ assert(np.isnan(div)), "dt: %s, div: %s" % (dt, div)
+ div = np.floor_divide(fnan, fzer)
+ assert(np.isnan(div)), "dt: %s, div: %s" % (dt, div)
# divide by zero error check
with np.errstate(divide='raise', invalid='ignore'):
assert_raises(FloatingPointError, np.floor_divide, y, x)
@@ -410,23 +420,72 @@ class TestRemainder:
div, mod = np.divmod(4, a)
np.isinf(div)
assert_(mod == 0)
+ with np.errstate(over='raise', invalid='ignore'):
+ assert_raises(FloatingPointError, np.divmod, 4, a)
+ with np.errstate(invalid='raise', over='ignore'):
+ assert_raises(FloatingPointError, np.divmod, 4, a)
+
+ def test_float_divmod_corner_cases(self):
+ # check nan cases
+ for dt in np.typecodes['Float']:
+ fnan = np.array(np.nan, dtype=dt)
+ fone = np.array(1.0, dtype=dt)
+ fzer = np.array(0.0, dtype=dt)
+ finf = np.array(np.inf, dtype=dt)
+ div, rem = np.divmod(fnan, fone)
+ assert(np.isnan(rem)), "dt: %s, rem: %s" % (dt, rem)
+ assert(np.isnan(div)), "dt: %s, rem: %s" % (dt, rem)
+ div, rem = np.divmod(fone, fnan)
+ assert(np.isnan(rem)), "dt: %s, rem: %s" % (dt, rem)
+ assert(np.isnan(div)), "dt: %s, rem: %s" % (dt, rem)
+ div, rem = np.divmod(fnan, fzer)
+ assert(np.isnan(rem)), "dt: %s, rem: %s" % (dt, rem)
+ assert(np.isnan(div)), "dt: %s, rem: %s" % (dt, rem)
+ with suppress_warnings() as sup:
+ sup.filter(RuntimeWarning, "invalid value encountered in divmod")
+ sup.filter(RuntimeWarning, "divide by zero encountered in divmod")
+ div, rem = np.divmod(fone, fzer)
+ assert(np.isinf(div)), 'dt: %s, div: %s' % (dt, rem)
+ assert(np.isnan(rem)), 'dt: %s, rem: %s' % (dt, rem)
+ div, rem = np.divmod(fzer, fzer)
+ assert(np.isnan(rem)), 'dt: %s, rem: %s' % (dt, rem)
+ assert_(np.isnan(div)), 'dt: %s, rem: %s' % (dt, rem)
+ div, rem = np.divmod(finf, finf)
+ assert(np.isnan(div)), 'dt: %s, rem: %s' % (dt, rem)
+ assert(np.isnan(rem)), 'dt: %s, rem: %s' % (dt, rem)
+ div, rem = np.divmod(finf, fzer)
+ assert(np.isinf(div)), 'dt: %s, rem: %s' % (dt, rem)
+ assert(np.isnan(rem)), 'dt: %s, rem: %s' % (dt, rem)
def test_float_remainder_corner_cases(self):
# Check remainder magnitude.
for dt in np.typecodes['Float']:
+ fone = np.array(1.0, dtype=dt)
+ fzer = np.array(0.0, dtype=dt)
+ fnan = np.array(np.nan, dtype=dt)
b = np.array(1.0, dtype=dt)
a = np.nextafter(np.array(0.0, dtype=dt), -b)
rem = np.remainder(a, b)
assert_(rem <= b, 'dt: %s' % dt)
rem = np.remainder(-a, -b)
assert_(rem >= -b, 'dt: %s' % dt)
+ rem = np.remainder(fone, fnan)
+ fmod = np.fmod(fone, fnan)
+ assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
+ assert_(np.isnan(fmod), 'dt: %s, fmod: %s' % (dt, fmod))
+ rem = np.remainder(fnan, fzer)
+ fmod = np.fmod(fnan, fzer)
+ assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
+ assert_(np.isnan(fmod), 'dt: %s, fmod: %s' % (dt, rem))
+ rem = np.remainder(fnan, fone)
+ fmod = np.fmod(fnan, fone)
+ assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
+ assert_(np.isnan(fmod), 'dt: %s, fmod: %s' % (dt, rem))
# Check nans, inf
with suppress_warnings() as sup:
sup.filter(RuntimeWarning, "invalid value encountered in remainder")
- sup.filter(RuntimeWarning, "invalid value encountered in divmod")
sup.filter(RuntimeWarning, "invalid value encountered in fmod")
- sup.filter(RuntimeWarning, "divide by zero encountered in divmod")
for dt in np.typecodes['Float']:
fone = np.array(1.0, dtype=dt)
fzer = np.array(0.0, dtype=dt)
@@ -434,25 +493,9 @@ class TestRemainder:
fnan = np.array(np.nan, dtype=dt)
rem = np.remainder(fone, fzer)
assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
- div, rem = np.divmod(fone, fzer)
- assert_(np.isinf(div), 'dt: %s, div: %s' % (dt, rem))
- assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
- div, rem = np.divmod(fzer, fzer)
- assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
- assert_(np.isnan(div), 'dt: %s, rem: %s' % (dt, rem))
- div, rem = np.divmod(finf, finf)
- assert_(np.isnan(div), 'dt: %s, rem: %s' % (dt, rem))
- assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
- div, rem = np.divmod(finf, fzer)
- assert_(np.isinf(div), 'dt: %s, rem: %s' % (dt, rem))
- assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
# MSVC 2008 returns NaN here, so disable the check.
#rem = np.remainder(fone, finf)
#assert_(rem == fone, 'dt: %s, rem: %s' % (dt, rem))
- rem = np.remainder(fone, fnan)
- fmod = np.fmod(fone, fnan)
- assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
- assert_(np.isnan(fmod), 'dt: %s, fmod: %s' % (dt, fmod))
rem = np.remainder(finf, fone)
fmod = np.fmod(finf, fone)
assert_(np.isnan(fmod), 'dt: %s, fmod: %s' % (dt, fmod))