diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c3a15d9..a799ed64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Pinned Cython in the Coverity Scan workflow so generated code stays stable between scans, and added `coverity/README.md` documenting the known Cython-boilerplate false positives and the scan review checklist [gh-266](https://github.com/IntelPython/mkl_umath/pull/266) ### Fixed +* Fixed `absolute` (float32/float64) returning `-NaN` for `+NaN` input on the scalar fallback path (same issue as numpy/numpy@dc478c58b9, gh-31433) [gh-269](https://github.com/IntelPython/mkl_umath/pull/269) * Fixed an over-decref of the borrowed module dictionary reference on the module initialization error path [gh-264](https://github.com/IntelPython/mkl_umath/pull/264) * Fixed a leak of the module object when the NumPy C-API import fails during module initialization [gh-263](https://github.com/IntelPython/mkl_umath/pull/263) diff --git a/mkl_umath/src/mkl_umath_loops.c.src b/mkl_umath/src/mkl_umath_loops.c.src index 5131d620..c1a41660 100644 --- a/mkl_umath/src/mkl_umath_loops.c.src +++ b/mkl_umath/src/mkl_umath_loops.c.src @@ -917,7 +917,7 @@ mkl_umath_@TYPE@_absolute(char **args, const npy_intp *dimensions, const npy_int else { UNARY_LOOP { const @type@ in1 = *(@type@ *)ip1; - const @type@ tmp = in1 > 0 ? in1 : -in1; + const @type@ tmp = fabs@c@(in1); /* add 0 to clear -0.0 */ *((@type@ *)op1) = tmp + 0; } diff --git a/mkl_umath/tests/test_basic.py b/mkl_umath/tests/test_basic.py index d2ab2d40..8433428c 100644 --- a/mkl_umath/tests/test_basic.py +++ b/mkl_umath/tests/test_basic.py @@ -189,3 +189,16 @@ def test_reduce_complex(func, dtype): assert np.allclose( mkl_res, np_res ), f"Results for '{func}[reduce]' do not match" + + +@pytest.mark.parametrize("size", [100, 8192 + 1]) +@pytest.mark.parametrize("dtype", [np.float32, np.float64]) +def test_absolute_nan_signbit(size, dtype): + # size 100 takes the fallback loop, 8193 takes MKL's vAbs + for nan in (np.nan, -np.nan): + a = np.full(size, nan, dtype=dtype) + sign = "-" if np.signbit(nan) else "+" + assert not np.signbit(mu.absolute(a)).any(), ( + f"absolute({sign}nan) must be +nan for " + f"{dtype.__name__} at size {size}" + )