diff options
author | Sayed Adel <seiko@imavr.com> | 2022-12-11 05:02:48 +0200 |
---|---|---|
committer | Sayed Adel <seiko@imavr.com> | 2022-12-14 20:23:22 +0200 |
commit | 14cd06f38852799603bf1a36460cc5bbab37ce2a (patch) | |
tree | af5c32b3f9690c40d0396fde8975f514db55514e | |
parent | e597f1bba7117c5e598f7e207f13ddd218dc94cd (diff) | |
download | numpy-14cd06f38852799603bf1a36460cc5bbab37ce2a.tar.gz |
ENH, TST: Test all FP unary ufunc against any unexpected fp exceptions
-rw-r--r-- | numpy/core/meson.build | 3 | ||||
-rw-r--r-- | numpy/core/tests/test_umath.py | 88 |
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]) |