summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2021-08-25 11:19:33 -0600
committerGitHub <noreply@github.com>2021-08-25 11:19:33 -0600
commit3712815c3209c4769ccad60de110f2bd8f3763ec (patch)
treea0c15c8d03af89e100548e3c6332d9a10ad9bf20
parent90ddaa5f88cab3b9143877aa1bb78f80fc38a9ac (diff)
parenta2a61e212fb1b8f27bc522b3769de93afdbb419d (diff)
downloadnumpy-3712815c3209c4769ccad60de110f2bd8f3763ec.tar.gz
Merge pull request #19621 from seberg/fix-normal-ufunc-safety
BUG: The normal cast-safety for ufunc loops is "no" casting
-rw-r--r--numpy/core/src/umath/legacy_array_method.c4
-rw-r--r--numpy/core/tests/test_ufunc.py31
2 files changed, 33 insertions, 2 deletions
diff --git a/numpy/core/src/umath/legacy_array_method.c b/numpy/core/src/umath/legacy_array_method.c
index a5e123baa..4351f1d25 100644
--- a/numpy/core/src/umath/legacy_array_method.c
+++ b/numpy/core/src/umath/legacy_array_method.c
@@ -142,7 +142,7 @@ simple_legacy_resolve_descriptors(
}
}
- return NPY_SAFE_CASTING;
+ return NPY_NO_CASTING;
fail:
for (int i = 0; i < nin + nout; i++) {
@@ -244,7 +244,7 @@ PyArray_NewLegacyWrappingArrayMethod(PyUFuncObject *ufunc,
.dtypes = signature,
.flags = flags,
.slots = slots,
- .casting = NPY_EQUIV_CASTING,
+ .casting = NPY_NO_CASTING,
};
PyBoundArrayMethodObject *bound_res = PyArrayMethod_FromSpec_int(&spec, 1);
diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py
index 657b6a79b..c3ea10d93 100644
--- a/numpy/core/tests/test_ufunc.py
+++ b/numpy/core/tests/test_ufunc.py
@@ -536,6 +536,37 @@ class TestUfunc:
np.add(arr, arr, dtype="m")
np.maximum(arr, arr, dtype="m")
+ @pytest.mark.parametrize("ufunc", [np.add, np.sqrt])
+ def test_cast_safety(self, ufunc):
+ """Basic test for the safest casts, because ufuncs inner loops can
+ indicate a cast-safety as well (which is normally always "no").
+ """
+ def call_ufunc(arr, **kwargs):
+ return ufunc(*(arr,) * ufunc.nin, **kwargs)
+
+ arr = np.array([1., 2., 3.], dtype=np.float32)
+ arr_bs = arr.astype(arr.dtype.newbyteorder())
+ expected = call_ufunc(arr)
+ # Normally, a "no" cast:
+ res = call_ufunc(arr, casting="no")
+ assert_array_equal(expected, res)
+ # Byte-swapping is not allowed with "no" though:
+ with pytest.raises(TypeError):
+ call_ufunc(arr_bs, casting="no")
+
+ # But is allowed with "equiv":
+ res = call_ufunc(arr_bs, casting="equiv")
+ assert_array_equal(expected, res)
+
+ # Casting to float64 is safe, but not equiv:
+ with pytest.raises(TypeError):
+ call_ufunc(arr_bs, dtype=np.float64, casting="equiv")
+
+ # but it is safe cast:
+ res = call_ufunc(arr_bs, dtype=np.float64, casting="safe")
+ expected = call_ufunc(arr.astype(np.float64)) # upcast
+ assert_array_equal(expected, res)
+
def test_true_divide(self):
a = np.array(10)
b = np.array(20)