diff --git a/quaddtype/numpy_quaddtype/src/casts.cpp b/quaddtype/numpy_quaddtype/src/casts.cpp index c43b89f0..e4da0ad9 100644 --- a/quaddtype/numpy_quaddtype/src/casts.cpp +++ b/quaddtype/numpy_quaddtype/src/casts.cpp @@ -502,6 +502,9 @@ template <> inline npy_byte from_quad(quad_value x, QuadBackendType backend) { + // runtime warnings often comes from/to casting of NaN, inf + // casting is used by ops at several positions leading to warnings + // fix can be catching the cases and returning corresponding type value without casting if (backend == BACKEND_SLEEF) { return (npy_byte)Sleef_cast_to_int64q1(x.sleef_value); } diff --git a/quaddtype/numpy_quaddtype/src/umath/comparison_ops.cpp b/quaddtype/numpy_quaddtype/src/umath/comparison_ops.cpp index 8ff2e661..ec285b86 100644 --- a/quaddtype/numpy_quaddtype/src/umath/comparison_ops.cpp +++ b/quaddtype/numpy_quaddtype/src/umath/comparison_ops.cpp @@ -200,7 +200,7 @@ create_quad_comparison_ufunc(PyObject *numpy, const char *ufunc_name) return -1; } - PyObject *DTypes = PyTuple_Pack(3, &PyArrayDescr_Type, &PyArrayDescr_Type, &PyArray_BoolDType); + PyObject *DTypes = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (DTypes == 0) { Py_DECREF(promoter_capsule); return -1; diff --git a/quaddtype/tests/test_quaddtype.py b/quaddtype/tests/test_quaddtype.py index d657d8df..27368e57 100644 --- a/quaddtype/tests/test_quaddtype.py +++ b/quaddtype/tests/test_quaddtype.py @@ -385,6 +385,67 @@ def test_array_minmax(op, a, b): assert np.signbit(float_res) == np.signbit( quad_res), f"Zero sign mismatch for {op}({a}, {b})" +class TestComparisonReductionOps: + """Test suite for comparison reduction operations on QuadPrecision arrays.""" + + @pytest.mark.parametrize("op", ["all", "any"]) + @pytest.mark.parametrize("input_array", [ + (["1.0", "2.0", "3.0"]), + (["1.0", "0.0", "3.0"]), + (["0.0", "0.0", "0.0"]), + # Including negative zero + (["-0.0", "0.0"]), + # Including NaN (should be treated as true) + (["nan", "1.0"]), + (["nan", "0.0"]), + (["nan", "nan"]), + # inf cases + (["inf", "1.0"]), + (["-inf", "0.0"]), + (["inf", "-inf"]), + # Mixed cases + (["1.0", "-0.0", "nan", "inf"]), + (["0.0", "-0.0", "nan", "-inf"]), + ]) + def test_reduction_ops(self, op, input_array): + """Test all and any reduction operations.""" + quad_array = np.array([QuadPrecision(x) for x in input_array]) + float_array = np.array([float(x) for x in input_array]) + op = getattr(np, op) + result = op(quad_array) + expected = op(float_array) + + assert result == expected, ( + f"Reduction op '{op}' failed for input {input_array}: " + f"expected {expected}, got {result}" + ) + + @pytest.mark.parametrize("val_str", [ + "0.0", + "-0.0", + "1.0", + "-1.0", + "nan", + "inf", + "-inf", + ]) + def test_scalar_reduction_ops(self, val_str): + """Test reduction operations on scalar QuadPrecision values.""" + quad_val = QuadPrecision(val_str) + float_val = np.float64(val_str) + + result_all = quad_val.all() + expected_all_result = float_val.all() + assert result_all == expected_all_result, ( + f"Scalar all failed for {val_str}: expected {expected_all_result}, got {result_all}" + ) + + result_any = quad_val.any() + expected_any_result = float_val.any() + assert result_any == expected_any_result, ( + f"Scalar any failed for {val_str}: expected {expected_any_result}, got {result_any}" + ) + # Logical operations tests @pytest.mark.parametrize("op", ["logical_and", "logical_or", "logical_xor"])