diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/src/npymath/npy_math_internal.h.src | 24 | ||||
-rw-r--r-- | numpy/core/tests/test_umath.py | 79 |
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)) |