diff options
| author | Charles Harris <charlesr.harris@gmail.com> | 2018-10-29 14:49:47 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-10-29 14:49:47 -0500 |
| commit | 96432eafbbdef03232d2f927d6c57c7285dda2f6 (patch) | |
| tree | 04cf29c7d43b9c6ec9378c49fc994aec6be39557 | |
| parent | 0dc45ecc707766c6983eae9b65e2bf518c487dc7 (diff) | |
| parent | 46452b360d9f67d6af78801a3957688515c617fe (diff) | |
| download | numpy-96432eafbbdef03232d2f927d6c57c7285dda2f6.tar.gz | |
Merge pull request #12236 from mattip/nan-warnings
BUG: maximum, minimum no longer emit warnings on NAN
| -rw-r--r-- | doc/release/1.16.0-notes.rst | 13 | ||||
| -rw-r--r-- | numpy/core/src/umath/loops.c.src | 35 | ||||
| -rw-r--r-- | numpy/core/src/umath/simd.inc.src | 10 | ||||
| -rw-r--r-- | numpy/core/tests/test_half.py | 18 | ||||
| -rw-r--r-- | numpy/core/tests/test_regression.py | 5 | ||||
| -rw-r--r-- | numpy/core/tests/test_umath.py | 19 |
6 files changed, 41 insertions, 59 deletions
diff --git a/doc/release/1.16.0-notes.rst b/doc/release/1.16.0-notes.rst index a5aa78740..3f2d887fe 100644 --- a/doc/release/1.16.0-notes.rst +++ b/doc/release/1.16.0-notes.rst @@ -288,12 +288,13 @@ if ``np.positive(array)`` raises a ``TypeError``. For ``ndarray`` subclasses that override the default ``__array_ufunc__`` implementation, the ``TypeError`` is passed on. -``maximum`` and ``minimum`` set invalid float status for more dtypes --------------------------------------------------------------------- -Previously only ``float32`` and ``float64`` set invalid float status (by -default emitting a `RuntimeWarning`) when a Nan is encountered in -`numpy.maximum` and `numpy.minimum`. Now ``float16``, ``complex64``, -``complex128`` and ``complex256`` will do so as well. +``maximum`` and ``minimum`` no longer emit warnings +--------------------------------------------------- +As part of code introduced in 1.10, ``float32`` and ``float64`` set invalid +float status when a Nan is encountered in `numpy.maximum` and `numpy.minimum`, +when using SSE2 semantics. This caused a `RuntimeWarning` to sometimes be +emitted. In 1.15 we fixed the inconsistencies which caused the warnings to +become more conspicuous. Now no warnings will be emitted. Umath and multiarray c-extension modules merged into a single module -------------------------------------------------------------------- diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index e62942efd..dd7feedc3 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -1833,10 +1833,7 @@ NPY_NO_EXPORT void if (!run_unary_reduce_simd_@kind@_@TYPE@(args, dimensions, steps)) { BINARY_REDUCE_LOOP(@type@) { const @type@ in2 = *(@type@ *)ip2; - io1 = (io1 @OP@ in2 || npy_isnan(io1)) ? io1 : in2; - } - if (npy_isnan(io1)) { - npy_set_floatstatus_invalid(); + io1 = (npy_isnan(io1) || io1 @OP@ in2) ? io1 : in2; } *((@type@ *)iop1) = io1; } @@ -1845,13 +1842,11 @@ NPY_NO_EXPORT void BINARY_LOOP { @type@ in1 = *(@type@ *)ip1; const @type@ in2 = *(@type@ *)ip2; - in1 = (in1 @OP@ in2 || npy_isnan(in1)) ? in1 : in2; - if (npy_isnan(in1)) { - npy_set_floatstatus_invalid(); - } + in1 = (npy_isnan(in1) || in1 @OP@ in2) ? in1 : in2; *((@type@ *)op1) = in1; } } + npy_clear_floatstatus_barrier((char*)dimensions); } /**end repeat1**/ @@ -1866,7 +1861,7 @@ NPY_NO_EXPORT void if (IS_BINARY_REDUCE) { BINARY_REDUCE_LOOP(@type@) { const @type@ in2 = *(@type@ *)ip2; - io1 = (io1 @OP@ in2 || npy_isnan(in2)) ? io1 : in2; + io1 = (npy_isnan(in2) || io1 @OP@ in2) ? io1 : in2; } *((@type@ *)iop1) = io1; } @@ -1874,7 +1869,7 @@ NPY_NO_EXPORT void BINARY_LOOP { const @type@ in1 = *(@type@ *)ip1; const @type@ in2 = *(@type@ *)ip2; - *((@type@ *)op1) = (in1 @OP@ in2 || npy_isnan(in2)) ? in1 : in2; + *((@type@ *)op1) = (npy_isnan(in2) || in1 @OP@ in2) ? in1 : in2; } } npy_clear_floatstatus_barrier((char*)dimensions); @@ -2195,14 +2190,11 @@ HALF_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED { /* */ BINARY_LOOP { - npy_half in1 = *(npy_half *)ip1; + const npy_half in1 = *(npy_half *)ip1; const npy_half in2 = *(npy_half *)ip2; - in1 = (@OP@(in1, in2) || npy_half_isnan(in1)) ? in1 : in2; - if (npy_half_isnan(in1)) { - npy_set_floatstatus_invalid(); - } - *((npy_half *)op1) = in1; + *((npy_half *)op1) = (@OP@(in1, in2) || npy_half_isnan(in1)) ? in1 : in2; } + /* npy_half_isnan will never set floatstatus_invalid, so do not clear */ } /**end repeat**/ @@ -2219,7 +2211,7 @@ HALF_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED const npy_half in2 = *(npy_half *)ip2; *((npy_half *)op1) = (@OP@(in1, in2) || npy_half_isnan(in2)) ? in1 : in2; } - npy_clear_floatstatus_barrier((char*)dimensions); + /* npy_half_isnan will never set floatstatus_invalid, so do not clear */ } /**end repeat**/ @@ -2761,16 +2753,14 @@ NPY_NO_EXPORT void @ftype@ in1i = ((@ftype@ *)ip1)[1]; const @ftype@ in2r = ((@ftype@ *)ip2)[0]; const @ftype@ in2i = ((@ftype@ *)ip2)[1]; - if ( !(@OP@(in1r, in1i, in2r, in2i) || npy_isnan(in1r) || npy_isnan(in1i))) { + if ( !(npy_isnan(in1r) || npy_isnan(in1i) || @OP@(in1r, in1i, in2r, in2i))) { in1r = in2r; in1i = in2i; } - if (npy_isnan(in1r) || npy_isnan(in1i)) { - npy_set_floatstatus_invalid(); - } ((@ftype@ *)op1)[0] = in1r; ((@ftype@ *)op1)[1] = in1i; } + npy_clear_floatstatus_barrier((char*)dimensions); } /**end repeat1**/ @@ -2786,7 +2776,7 @@ NPY_NO_EXPORT void const @ftype@ in1i = ((@ftype@ *)ip1)[1]; const @ftype@ in2r = ((@ftype@ *)ip2)[0]; const @ftype@ in2i = ((@ftype@ *)ip2)[1]; - if (@OP@(in1r, in1i, in2r, in2i) || npy_isnan(in2r) || npy_isnan(in2i)) { + if (npy_isnan(in2r) || npy_isnan(in2i) || @OP@(in1r, in1i, in2r, in2i)) { ((@ftype@ *)op1)[0] = in1r; ((@ftype@ *)op1)[1] = in1i; } @@ -2795,6 +2785,7 @@ NPY_NO_EXPORT void ((@ftype@ *)op1)[1] = in2i; } } + npy_clear_floatstatus_barrier((char*)dimensions); } /**end repeat1**/ diff --git a/numpy/core/src/umath/simd.inc.src b/numpy/core/src/umath/simd.inc.src index 47f9168e5..da0713b2b 100644 --- a/numpy/core/src/umath/simd.inc.src +++ b/numpy/core/src/umath/simd.inc.src @@ -1014,7 +1014,7 @@ sse2_@kind@_@TYPE@(@type@ * ip, @type@ * op, const npy_intp n) { const npy_intp stride = 16 / (npy_intp)sizeof(@type@); LOOP_BLOCK_ALIGN_VAR(ip, @type@, 16) { - *op = (*op @OP@ ip[i] || npy_isnan(*op)) ? *op : ip[i]; + *op = (npy_isnan(*op) || *op @OP@ ip[i]) ? *op : ip[i]; } assert(n < (stride) || npy_is_aligned(&ip[i], 16)); if (i + 3 * stride <= n) { @@ -1038,15 +1038,13 @@ sse2_@kind@_@TYPE@(@type@ * ip, @type@ * op, const npy_intp n) } else { @type@ tmp = sse2_horizontal_@VOP@_@vtype@(c1); - *op = (*op @OP@ tmp || npy_isnan(*op)) ? *op : tmp; + *op = (npy_isnan(*op) || *op @OP@ tmp) ? *op : tmp; } } LOOP_BLOCKED_END { - *op = (*op @OP@ ip[i] || npy_isnan(*op)) ? *op : ip[i]; - } - if (npy_isnan(*op)) { - npy_set_floatstatus_invalid(); + *op = (npy_isnan(*op) || *op @OP@ ip[i]) ? *op : ip[i]; } + npy_clear_floatstatus_barrier((char*)op); } /**end repeat1**/ diff --git a/numpy/core/tests/test_half.py b/numpy/core/tests/test_half.py index d715569f8..2f2d069e5 100644 --- a/numpy/core/tests/test_half.py +++ b/numpy/core/tests/test_half.py @@ -301,21 +301,19 @@ class TestHalf(object): assert_equal(np.copysign(b, a), [2, 5, 1, 4, 3]) assert_equal(np.maximum(a, b), [0, 5, 2, 4, 3]) - with suppress_warnings() as sup: - sup.record(RuntimeWarning) - x = np.maximum(b, c) - assert_(np.isnan(x[3])) - assert_equal(len(sup.log), 1) + + x = np.maximum(b, c) + assert_(np.isnan(x[3])) x[3] = 0 assert_equal(x, [0, 5, 1, 0, 6]) + assert_equal(np.minimum(a, b), [-2, 1, 1, 4, 2]) - with suppress_warnings() as sup: - sup.record(RuntimeWarning) - x = np.minimum(b, c) - assert_(np.isnan(x[3])) - assert_equal(len(sup.log), 1) + + x = np.minimum(b, c) + assert_(np.isnan(x[3])) x[3] = 0 assert_equal(x, [-2, -1, -np.inf, 0, 3]) + assert_equal(np.fmax(a, b), [0, 5, 2, 4, 3]) assert_equal(np.fmax(b, c), [0, 5, 1, 4, 6]) assert_equal(np.fmin(a, b), [-2, 1, 1, 4, 2]) diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index d53f6da84..a929b0efd 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -1557,10 +1557,7 @@ class TestRegression(object): def test_complex_nan_maximum(self): cnan = complex(0, np.nan) - with suppress_warnings() as sup: - sup.record(RuntimeWarning) - assert_equal(np.maximum(1, cnan), cnan) - assert_equal(len(sup.log), 1) + assert_equal(np.maximum(1, cnan), cnan) def test_subclass_int_tuple_assignment(self): # ticket #1563 diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py index c15ce83f6..bd7985dfb 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -1327,21 +1327,18 @@ class TestMinMax(object): assert_equal(d.max(), d[0]) assert_equal(d.min(), d[0]) - def test_reduce_warns(self): + def test_reduce_reorder(self): # gh 10370, 11029 Some compilers reorder the call to npy_getfloatstatus # and put it before the call to an intrisic function that causes - # invalid status to be set. Also make sure warnings are emitted + # invalid status to be set. Also make sure warnings are not emitted for n in (2, 4, 8, 16, 32): for dt in (np.float32, np.float16, np.complex64): - with suppress_warnings() as sup: - sup.record(RuntimeWarning) - for r in np.diagflat(np.array([np.nan] * n, dtype=dt)): - assert_equal(np.min(r), np.nan) - assert_equal(len(sup.log), n) - - def test_minimize_warns(self): - # gh 11589 - assert_warns(RuntimeWarning, np.minimum, np.nan, 1) + for r in np.diagflat(np.array([np.nan] * n, dtype=dt)): + assert_equal(np.min(r), np.nan) + + def test_minimize_no_warns(self): + a = np.minimum(np.nan, 1) + assert_equal(a, np.nan) class TestAbsoluteNegative(object): |
