summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSayed Adel <seiko@imavr.com>2022-12-11 05:02:48 +0200
committerSayed Adel <seiko@imavr.com>2022-12-14 20:23:22 +0200
commit14cd06f38852799603bf1a36460cc5bbab37ce2a (patch)
treeaf5c32b3f9690c40d0396fde8975f514db55514e
parente597f1bba7117c5e598f7e207f13ddd218dc94cd (diff)
downloadnumpy-14cd06f38852799603bf1a36460cc5bbab37ce2a.tar.gz
ENH, TST: Test all FP unary ufunc against any unexpected fp exceptions
-rw-r--r--numpy/core/meson.build3
-rw-r--r--numpy/core/tests/test_umath.py88
2 files changed, 80 insertions, 11 deletions
diff --git a/numpy/core/meson.build b/numpy/core/meson.build
index 50cd8ccc5..d1de331ff 100644
--- a/numpy/core/meson.build
+++ b/numpy/core/meson.build
@@ -133,7 +133,7 @@ mandatory_funcs = [
'floor', 'ceil', 'sqrt', 'log10', 'log', 'exp', 'asin',
'acos', 'atan', 'fmod', 'modf', 'frexp', 'ldexp',
'expm1', 'log1p', 'acosh', 'asinh', 'atanh',
- 'rint', 'trunc', 'exp2',
+ 'rint', 'trunc', 'exp2',
'copysign', 'nextafter', 'strtoll', 'strtoull', 'cbrt',
'log2', 'pow', 'hypot', 'atan2',
'csin', 'csinh', 'ccos', 'ccosh', 'ctan', 'ctanh',
@@ -867,6 +867,7 @@ py.extension_module('_simd',
#include_directories: ['src/multiarray', 'src/npymath'],
include_directories: ['src/_simd'],
dependencies: np_core_dep,
+ link_with: npymath_lib,
install: true,
subdir: 'numpy/core',
)
diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py
index 88ab7e014..073a370c0 100644
--- a/numpy/core/tests/test_umath.py
+++ b/numpy/core/tests/test_umath.py
@@ -21,6 +21,15 @@ from numpy.testing import (
)
from numpy.testing._private.utils import _glibc_older_than
+UFUNCS = [obj for obj in np.core.umath.__dict__.values()
+ if isinstance(obj, np.ufunc)]
+
+UFUNCS_UNARY = [
+ uf for uf in UFUNCS if uf.nin == 1
+]
+UFUNCS_UNARY_FP = [
+ uf for uf in UFUNCS_UNARY if 'f->f' in uf.types
+]
def interesting_binop_operands(val1, val2, dtype):
"""
@@ -1086,7 +1095,7 @@ class TestPower:
assert_complex_equal(np.power(zero, 1+1j), zero)
assert_complex_equal(np.power(zero, 1+0j), zero)
assert_complex_equal(np.power(zero, 1-1j), zero)
- #Complex powers will negative real part or 0 (provided imaginary
+ #Complex powers will negative real part or 0 (provided imaginary
# part is not zero) will generate a NAN and hence a RUNTIME warning
with pytest.warns(expected_warning=RuntimeWarning) as r:
assert_complex_equal(np.power(zero, -1+1j), cnan)
@@ -1631,15 +1640,74 @@ class TestSpecialFloats:
np.array(value, dtype=dt))
# test to ensure no spurious FP exceptions are raised due to SIMD
- def test_spurious_fpexception(self):
- for dt in ['e', 'f', 'd']:
- arr = np.array([1.0, 2.0], dtype=dt)
- with assert_no_warnings():
- np.log(arr)
- np.log2(arr)
- np.log10(arr)
- np.arccosh(arr)
-
+ INF_INVALID_ERR = [
+ np.cos, np.sin, np.tan, np.arccos, np.arcsin, np.spacing, np.arctanh
+ ]
+ NEG_INVALID_ERR = [
+ np.log, np.log2, np.log10, np.log1p, np.sqrt, np.arccosh,
+ np.arctanh
+ ]
+ ONE_INVALID_ERR = [
+ np.arctanh,
+ ]
+ LTONE_INVALID_ERR = [
+ np.arccosh,
+ ]
+ BYZERO_ERR = [
+ np.log, np.log2, np.log10, np.reciprocal, np.arccosh
+ ]
+
+ @pytest.mark.parametrize("ufunc", UFUNCS_UNARY_FP)
+ @pytest.mark.parametrize("dtype", ('e', 'f', 'd'))
+ @pytest.mark.parametrize("data, escape", (
+ ([0.03], LTONE_INVALID_ERR),
+ ([0.03]*32, LTONE_INVALID_ERR),
+ # neg
+ ([-1.0], NEG_INVALID_ERR),
+ ([-1.0]*32, NEG_INVALID_ERR),
+ # flat
+ ([1.0], ONE_INVALID_ERR),
+ ([1.0]*32, ONE_INVALID_ERR),
+ # zero
+ ([0.0], BYZERO_ERR),
+ ([0.0]*32, BYZERO_ERR),
+ ([-0.0], BYZERO_ERR),
+ ([-0.0]*32, BYZERO_ERR),
+ # nan
+ ([0.5, 0.5, 0.5, np.nan], LTONE_INVALID_ERR),
+ ([0.5, 0.5, 0.5, np.nan]*32, LTONE_INVALID_ERR),
+ ([np.nan, 1.0, 1.0, 1.0], ONE_INVALID_ERR),
+ ([np.nan, 1.0, 1.0, 1.0]*32, ONE_INVALID_ERR),
+ ([np.nan], []),
+ ([np.nan]*32, []),
+ # inf
+ ([0.5, 0.5, 0.5, np.inf], INF_INVALID_ERR + LTONE_INVALID_ERR),
+ ([0.5, 0.5, 0.5, np.inf]*32, INF_INVALID_ERR + LTONE_INVALID_ERR),
+ ([np.inf, 1.0, 1.0, 1.0], INF_INVALID_ERR),
+ ([np.inf, 1.0, 1.0, 1.0]*32, INF_INVALID_ERR),
+ ([np.inf], INF_INVALID_ERR),
+ ([np.inf]*32, INF_INVALID_ERR),
+ # ninf
+ ([0.5, 0.5, 0.5, -np.inf],
+ NEG_INVALID_ERR + INF_INVALID_ERR + LTONE_INVALID_ERR),
+ ([0.5, 0.5, 0.5, -np.inf]*32,
+ NEG_INVALID_ERR + INF_INVALID_ERR + LTONE_INVALID_ERR),
+ ([-np.inf, 1.0, 1.0, 1.0], NEG_INVALID_ERR + INF_INVALID_ERR),
+ ([-np.inf, 1.0, 1.0, 1.0]*32, NEG_INVALID_ERR + INF_INVALID_ERR),
+ ([-np.inf], NEG_INVALID_ERR + INF_INVALID_ERR),
+ ([-np.inf]*32, NEG_INVALID_ERR + INF_INVALID_ERR),
+ ))
+ def test_unary_spurious_fpexception(self, ufunc, dtype, data, escape):
+ if escape and ufunc in escape:
+ return
+ # FIXME: NAN raises FP invalid exception:
+ # - ceil/float16 on MSVC:32-bit
+ # - spacing/float16 on almost all platforms
+ if ufunc in (np.spacing, np.ceil) and dtype == 'e':
+ return
+ array = np.array(data, dtype=dtype)
+ with assert_no_warnings():
+ ufunc(array)
class TestFPClass:
@pytest.mark.parametrize("stride", [-4,-2,-1,1,2,4])