summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--numpy/core/code_generators/generate_umath.py51
-rw-r--r--numpy/core/tests/test_umath.py8
2 files changed, 54 insertions, 5 deletions
diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py
index bf1a05ee4..6930b49da 100644
--- a/numpy/core/code_generators/generate_umath.py
+++ b/numpy/core/code_generators/generate_umath.py
@@ -90,6 +90,41 @@ class TypeDescription:
assert len(self.out) == nout
self.astype = self.astype_dict.get(self.type, None)
+
+def _check_order(types1, types2):
+ dtype_order = allP + "O"
+ for t1, t2 in zip(types1, types2):
+ # We have no opinion on object or time ordering for now:
+ if t1 in "OP" or t2 in "OP":
+ return True
+ if t1 in "mM" or t2 in "mM":
+ return True
+
+ t1i = dtype_order.index(t1)
+ t2i = dtype_order.index(t2)
+ if t1i < t2i:
+ return
+ if t2i > t1i:
+ break
+
+ raise TypeError(
+ f"Input dtypes are unsorted or duplicate: {types1} and {types2}")
+
+
+def check_td_order(tds):
+ # A quick check for whether the signatures make sense, it happened too
+ # often that SIMD additions added loops that do not even make some sense.
+ # TODO: This should likely be a test and it would be nice if it rejected
+ # duplicate entries as well (but we have many as of writing this).
+ signatures = [t.in_+t.out for t in tds]
+
+ for prev_i, sign in enumerate(signatures[1:]):
+ if sign in signatures[:prev_i+1]:
+ continue # allow duplicates...
+
+ _check_order(signatures[prev_i], sign)
+
+
_fdata_map = dict(
e='npy_%sf',
f='npy_%sf',
@@ -173,6 +208,9 @@ class Ufunc:
for td in self.type_descriptions:
td.finish_signature(self.nin, self.nout)
+ check_td_order(self.type_descriptions)
+
+
# String-handling utilities to avoid locale-dependence.
import string
@@ -719,18 +757,20 @@ defdict = {
Ufunc(1, 1, None,
docstrings.get('numpy.core.umath.cos'),
None,
+ TD('e', dispatch=[('loops_umath_fp', 'e')]),
TD('f', dispatch=[('loops_trigonometric', 'f')]),
- TD('ed', dispatch=[('loops_umath_fp', 'ed')]),
- TD('fdg' + cmplx, f='cos'),
+ TD('d', dispatch=[('loops_umath_fp', 'd')]),
+ TD('g' + cmplx, f='cos'),
TD(P, f='cos'),
),
'sin':
Ufunc(1, 1, None,
docstrings.get('numpy.core.umath.sin'),
None,
+ TD('e', dispatch=[('loops_umath_fp', 'e')]),
TD('f', dispatch=[('loops_trigonometric', 'f')]),
- TD('ed', dispatch=[('loops_umath_fp', 'ed')]),
- TD('fdg' + cmplx, f='sin'),
+ TD('d', dispatch=[('loops_umath_fp', 'd')]),
+ TD('g' + cmplx, f='sin'),
TD(P, f='sin'),
),
'tan':
@@ -888,8 +928,9 @@ defdict = {
Ufunc(2, 1, None,
docstrings.get('numpy.core.umath.arctan2'),
None,
+ TD('e', f='atan2', astype={'e': 'f'}),
TD('fd', dispatch=[('loops_umath_fp', 'fd')]),
- TD(flts, f='atan2', astype={'e': 'f'}),
+ TD('g', f='atan2', astype={'e': 'f'}),
TD(P, f='arctan2'),
),
'remainder':
diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py
index 26e4e39af..65c0310da 100644
--- a/numpy/core/tests/test_umath.py
+++ b/numpy/core/tests/test_umath.py
@@ -4027,6 +4027,14 @@ class TestComplexFunctions:
check(func, pts, 1j)
check(func, pts, 1+1j)
+ @np.errstate(all="ignore")
+ def test_promotion_corner_cases(self):
+ for func in self.funcs:
+ assert func(np.float16(1)).dtype == np.float16
+ # Integer to low precision float promotion is a dubious choice:
+ assert func(np.uint8(1)).dtype == np.float16
+ assert func(np.int16(1)).dtype == np.float32
+
class TestAttributes:
def test_attributes(self):