diff --git a/quaddtype/numpy_quaddtype/src/ops.hpp b/quaddtype/numpy_quaddtype/src/ops.hpp index efa33f9b..6fa5342b 100644 --- a/quaddtype/numpy_quaddtype/src/ops.hpp +++ b/quaddtype/numpy_quaddtype/src/ops.hpp @@ -37,6 +37,13 @@ quad_absolute(const Sleef_quad *op) return Sleef_fabsq1(*op); } +static inline Sleef_quad +quad_conjugate(const Sleef_quad *op) +{ + // For real numbers, conjugate is the identity function (no-op) + return *op; +} + static inline Sleef_quad quad_rint(const Sleef_quad *op) { @@ -217,6 +224,13 @@ ld_absolute(const long double *op) return fabsl(*op); } +static inline long double +ld_conjugate(const long double *op) +{ + // For real numbers, conjugate is the identity function (no-op) + return *op; +} + static inline long double ld_sign(const long double *op) { diff --git a/quaddtype/numpy_quaddtype/src/umath/unary_ops.cpp b/quaddtype/numpy_quaddtype/src/umath/unary_ops.cpp index b8a82aee..3c343fef 100644 --- a/quaddtype/numpy_quaddtype/src/umath/unary_ops.cpp +++ b/quaddtype/numpy_quaddtype/src/umath/unary_ops.cpp @@ -161,6 +161,11 @@ init_quad_unary_ops(PyObject *numpy) if (create_quad_unary_ufunc(numpy, "fabs") < 0) { return -1; } + // conjugate is a no-op for real numbers (returns the value unchanged) + if (create_quad_unary_ufunc(numpy, "conjugate") < 0) { + return -1; + } + // conj is an alias for conjugate, no need to register if (create_quad_unary_ufunc(numpy, "sign") < 0) { return -1; } diff --git a/quaddtype/release_tracker.md b/quaddtype/release_tracker.md index 29e6cebb..6a845a34 100644 --- a/quaddtype/release_tracker.md +++ b/quaddtype/release_tracker.md @@ -27,6 +27,9 @@ | rint | ✅ | ✅ | | sign | ✅ | ✅ | | heaviside | ✅ | ✅ | +| conj | ✅ | ✅ | +| conjugate | ✅ | ✅ | +| heaviside | ✅ | ✅ | | conj | | | | conjugate | | | | exp | ✅ | ✅ | @@ -40,8 +43,6 @@ | square | ✅ | ✅ | | cbrt | | | | reciprocal | ✅ | ✅ | -| gcd | | | -| lcm | | | | sin | ✅ | ❌ _Need: basic tests + edge cases (NaN/inf/0/π multiples/2π range)_ | | cos | ✅ | ❌ _Need: basic tests + edge cases (NaN/inf/0/π multiples/2π range)_ | | tan | ✅ | ❌ _Need: basic tests + edge cases (NaN/inf/0/π/2 asymptotes)_ | diff --git a/quaddtype/tests/test_quaddtype.py b/quaddtype/tests/test_quaddtype.py index b1fbb0bc..e27ea8dc 100644 --- a/quaddtype/tests/test_quaddtype.py +++ b/quaddtype/tests/test_quaddtype.py @@ -1693,3 +1693,25 @@ def test_heaviside_broadcast(): assert result.dtype.name == "QuadPrecDType128" np.testing.assert_array_equal(result.astype(float), expected) + +@pytest.mark.parametrize("func", [np.conj, np.conjugate]) +@pytest.mark.parametrize("value", [ + 0.0, + -0.0, + 1.5, + -1.5, + np.inf, + -np.inf, + np.nan, +]) +def test_conj_conjugate_identity(func, value): + """Test that conj and conjugate are identity (no-op) for real quad precision numbers""" + x = QuadPrecision(value) + result = func(x) + + # For NaN, use special comparison + if np.isnan(value): + assert np.isnan(float(result)) + else: + assert result == x +