8000 Merge pull request #12236 from mattip/nan-warnings · numpy/numpy@96432ea · GitHub
[go: up one dir, main page]

Skip to content

Commit 96432ea

Browse files
authored
Merge pull request #12236 from mattip/nan-warnings
BUG: maximum, minimum no longer emit warnings on NAN
2 parents 0dc45ec + 46452b3 commit 9643
10000
2ea

File tree

6 files changed

+41
-59
lines changed

6 files changed

+41
-59
lines changed

doc/release/1.16.0-notes.rst

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -288,12 +288,13 @@ if ``np.positive(array)`` raises a ``TypeError``. For ``ndarray``
288288
subclasses that override the default ``__array_ufunc__`` implementation,
289289
the ``TypeError`` is passed on.
290290

291-
``maximum`` and ``minimum`` set invalid float status for more dtypes
292-
--------------------------------------------------------------------
293-
Previously only ``float32`` and ``float64`` set invalid float status (by
294-
default emitting a `RuntimeWarning`) when a Nan is encountered in
295-
`numpy.maximum` and `numpy.minimum`. Now ``float16``, ``complex64``,
296-
``complex128`` and ``complex256`` will do so as well.
291+
``maximum`` and ``minimum`` no longer emit warnings
292+
---------------------------------------------------
293+
As part of code introduced in 1.10, ``float32`` and ``float64`` set invalid
294+
float status when a Nan is encountered in `numpy.maximum` and `numpy.minimum`,
295+
when using SSE2 semantics. This caused a `RuntimeWarning` to sometimes be
296+
emitted. In 1.15 we fixed the inconsistencies which caused the warnings to
297+
become more conspicuous. Now no warnings will be emitted.
297298

298299
Umath and multiarray c-extension modules merged into a single module
299300
--------------------------------------------------------------------

numpy/core/src/umath/loops.c.src

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1833,10 +1833,7 @@ NPY_NO_EXPORT void
18331833
if (!run_unary_reduce_simd_@kind@_@TYPE@(args, dimensions, steps)) {
18341834
BINARY_REDUCE_LOOP(@type@) {
18351835
const @type@ in2 = *(@type@ *)ip2;
1836-
io1 = (io1 @OP@ in2 || npy_isnan(io1)) ? io1 : in2;
1837-
}
1838-
if (npy_isnan(io1)) {
1839-
npy_set_floatstatus_invalid();
1836+
io1 = (npy_isnan(io1) || io1 @OP@ in2) ? io1 : in2;
18401837
}
18411838
*((@type@ *)iop1) = io1; 8000
18421839
}
@@ -1845,13 +1842,11 @@ NPY_NO_EXPORT void
18451842
BINARY_LOOP {
18461843
@type@ in1 = *(@type@ *)ip1;
18471844
const @type@ in2 = *(@type@ *)ip2;
1848-
in1 = (in1 @OP@ in2 || npy_isnan(in1)) ? in1 : in2;
1849-
if (npy_isnan(in1)) {
1850-
npy_set_floatstatus_invalid();
1851-
}
1845+
in1 = (npy_isnan(in1) || in1 @OP@ in2) ? in1 : in2;
18521846
*((@type@ *)op1) = in1;
18531847
}
18541848
}
1849+
npy_clear_floatstatus_barrier((char*)dimensions);
18551850
}
18561851
/**end repeat1**/
18571852

@@ -1866,15 +1861,15 @@ NPY_NO_EXPORT void
18661861
if (IS_BINARY_REDUCE) {
18671862
BINARY_REDUCE_LOOP(@type@) {
18681863
const @type@ in2 = *(@type@ *)ip2;
1869-
io1 = (io1 @OP@ in2 || npy_isnan(in2)) ? io1 : in2;
1864+
io1 = (npy_isnan(in2) || io1 @OP@ in2) ? io1 : in2;
18701865
}
18711866
*((@type@ *)iop1) = io1;
18721867
}
18731868
else {
18741869
BINARY_LOOP {
18751870
const @type@ in1 = *(@type@ *)ip1;
18761871
const @type@ in2 = *(@type@ *)ip2;
1877-
*((@type@ *)op1) = (in1 @OP@ in2 || npy_isnan(in2)) ? in1 : in2;
1872+
*((@type@ *)op1) = (npy_isnan(in2) || in1 @OP@ in2) ? in1 : in2;
18781873
}
18791874
}
18801875
npy_clear_floatstatus_barrier((char*)dimensions);
@@ -2195,14 +2190,11 @@ HALF_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED
21952190
{
21962191
/* */
21972192
BINARY_LOOP {
2198-
npy_half in1 = *(npy_half *)ip1;
2193+
const npy_half in1 = *(npy_half *)ip1;
21992194
const npy_half in2 = *(npy_half *)ip2;
2200-
in1 = (@OP@(in1, in2) || npy_half_isnan(in1)) ? in1 : in2;
2201-
if (npy_half_isnan(in1)) {
2202-
npy_set_floatstatus_invalid();
2203-
}
2204-
*((npy_half *)op1) = in1;
2195+
*((npy_half *)op1) = (@OP@(in1, in2) || npy_half_isnan(in1)) ? in1 : in2;
22052196
}
2197+
/* npy_half_isnan will never set floatstatus_invalid, so do not clear */
22062198
}
22072199
/**end repeat**/
22082200

@@ -2219,7 +2211,7 @@ HALF_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED
22192211
const npy_half in2 = *(npy_half *)ip2;
22202212
*((npy_half *)op1) = (@OP@(in1, in2) || npy_half_isnan(in2)) ? in1 : in2;
22212213
}
2222-
npy_clear_floatstatus_barrier((char*)dimensions);
2214+
/* npy_half_isnan will never set floatstatus_invalid, so do not clear */
22232215
}
22242216
/**end repeat**/
22252217

@@ -2761,16 +2753,14 @@ NPY_NO_EXPORT void
27612753
@ftype@ in1i = ((@ftype@ *)ip1)[1];
27622754
const @ftype@ in2r = ((@ftype@ *)ip2)[0];
27632755
const @ftype@ in2i = ((@ftype@ *)ip2)[1];
2764-
if ( !(@OP@(in1r, in1i, in2r, in2i) || npy_isnan(in1r) || npy_isnan(in1i))) {
2756+
if ( !(npy_isnan(in1r) || npy_isnan(in1i) || @OP@(in1r, in1i, in2r, in2i))) {
27652757
in1r = in2r;
27662758
in1i = in2i;
27672759
}
2768-
if (npy_isnan(in1r) || npy_isnan(in1i)) {
2769-
npy_set_floatstatus_invalid();
2770-
}
27712760
((@ftype@ *)op1)[0] = in1r;
27722761
((@ftype@ *)op1)[1] = in1i;
27732762
}
2763+
npy_clear_floatstatus_barrier((char*)dimensions);
27742764
}
27752765
/**end repeat1**/
27762766

@@ -2786,7 +2776,7 @@ NPY_NO_EXPORT void
27862776
const @ftype@ in1i = ((@ftype@ *)ip1)[1];
27872777
const @ftype@ in2r = ((@ftype@ *)ip2)[0];
27882778
const @ftype@ in2i = ((@ftype@ *)ip2)[1];
2789-
if (@OP@(in1r, in1i, in2r, in2i) || npy_isnan(in2r) || npy_isnan(in2i)) {
2779+
if (npy_isnan(in2r) || npy_isnan(in2i) || @OP@(in1r, in1i, in2r, in2i)) {
27902780
((@ftype@ *)op1)[0] = in1r;
27912781
((@ftype@ *)op1)[1] = in1i;
27922782
}
@@ -2795,6 +2785,7 @@ NPY_NO_EXPORT void
27952785
((@ftype@ *)op1)[1] = in2i;
27962786
}
27972787
}
2788+
npy_clear_floatstatus_barrier((char*)dimensions);
27982789
}
27992790
/**end repeat1**/
28002791

numpy/core/src/umath/simd.inc.src

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,7 @@ sse2_@kind@_@TYPE@(@type@ * ip, @type@ * op, const npy_intp n)
10141014
{
10151015
const npy_intp stride = 16 / (npy_intp)sizeof(@type@);
10161016
LOOP_BLOCK_ALIGN_VAR(ip, @type@, 16) {
1017-
*op = (*op @OP@ ip[i] || npy_isnan(*op)) ? *op : ip[i];
1017+
*op = (npy_isnan(*op) || *op @OP@ ip[i]) ? *op : ip[i];
10181018
}
10191019
assert(n < (stride) || npy_is_aligned(&ip[i], 16));
10201020
if (i + 3 * stride <= n) {
@@ -1038,15 +1038,13 @@ sse2_@kind@_@TYPE@(@type@ * ip, @type@ * op, const npy_intp n)
10381038
}
10391039
else {
10401040
@type@ tmp = sse2_horizontal_@VOP@_@vtype@(c1);
1041-
*op = (*op @OP@ tmp || npy_isnan(*op)) ? *op : tmp;
1041+
*op = (npy_isnan(*op) || *op @OP@ tmp) ? *op : tmp;
10421042
}
10431043
}
10441044
LOOP_BLOCKED_END {
1045-
*op = (*op @OP@ ip[i] || npy_isnan(*op)) ? *op : ip[i];
1046-
}
1047-
if (npy_isnan(*op)) {
1048-
npy_set_floatstatus_invalid();
1045+
*op = (npy_isnan(*op) || *op @OP@ ip[i]) ? *op : ip[i];
10491046
}
1047+
npy_clear_floatstatus_barrier((char*)op);
10501048
}
10511049
/**end repeat1**/
10521050

numpy/core/tests/test_half.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -301,21 +301,19 @@ def test_half_ufuncs(self):
301301
assert_equal(np.copysign(b, a), [2, 5, 1, 4, 3])
302302

303303
assert_equal(np.maximum(a, b), [0, 5, 2, 4, 3])
304-
with suppress_warnings() as sup:
305-
sup.record(RuntimeWarning)
306-
x = np.maximum(b, c)
307-
assert_(np.isnan(x[3]))
308-
assert_equal(len(sup.log), 1)
304+
305+
x = np.maximum(b, c)
306+
assert_(np.isnan(x[3]))
309307
x[3] = 0
310308
assert_equal(x, [0, 5, 1, 0, 6])
309+
311310
assert_equal(np.minimum(a, b), [-2, 1, 1, 4, 2])
312-
with suppress_warnings() as sup:
313-
sup.record(RuntimeWarning)
314-
x = np.minimum(b, c)
315-
assert_(np.isnan(x[3]))
316-
assert_equal(len(sup.log), 1)
311+
312+
x = np.minimum(b, c)
313+
assert_(np.isnan(x[3]))
317314
x[3] = 0
318315
assert_equal(x, [-2, -1, -np.inf, 0, 3])
316+
319317
assert_equal(np.fmax(a, b), [0, 5, 2, 4, 3])
320318
assert_equal(np.fmax(b, c), [0, 5, 1, 4, 6])
321319
assert_equal(np.fmin(a, b), [-2, 1, 1, 4, 2])

numpy/core/tests/test_regression.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,10 +1557,7 @@ def test_ticket_1434(self):
15571557

15581558
def test_complex_nan_maximum(self):
15591559
cnan = complex(0, np.nan)
1560-
with suppress_warnings() as sup:
1561-
sup.record(RuntimeWarning)
1562-
assert_equal(np.maximum(1, cnan), cnan)
1563-
assert_equal(len(sup.log), 1)
1560+
assert_equal(np.maximum(1, cnan), cnan)
15641561

15651562
def test_subclass_int_tuple_assignment(self):
15661563
# ticket #1563

numpy/core/tests/test_umath.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,21 +1327,18 @@ def test_lower_align(self):
13271327
assert_equal(d.max(), d[0])
13281328
assert_equal(d.min(), d[0])
13291329

1330-
def test_reduce_warns(self):
1330+
def test_reduce_reorder(self):
13311331
# gh 10370, 11029 Some compilers reorder the call to npy_getfloatstatus
13321332
# and put it before the call to an intrisic function that causes
1333-
# invalid status to be set. Also make sure warnings are emitted
1333+
# invalid status to be set. Also make sure warnings are not emitted
13341334
for n in (2, 4, 8, 16, 32):
13351335
for dt in (np.float32, np.float16, np.complex64):
1336-
with suppress_warnings() as sup:
1337-
sup.record(RuntimeWarning)
1338-
for r in np.diagflat(np.array([np.nan] * n, dtype=dt)):
1339-
assert_equal(np.min(r), np.nan)
1340-
assert_equal(len(sup.log), n)
1341-
1342-
def test_minimize_warns(self):
1343-
# gh 11589
1344-
assert_warns(RuntimeWarning, np.minimum, np.nan, 1)
1336+
for r in np.diagflat(np.array([np.nan] * n, dtype=dt)):
1337+
assert_equal(np.min(r), np.nan)
1338+
1339+
def test_minimize_no_warns(self):
1340+
a = np.minimum(np.nan, 1)
1341+
assert_equal(a, np.nan)
13451342

13461343

13471344
class TestAbsoluteNegative(object):

0 commit comments

Comments
 (0)
0