Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions quaddtype/numpy_quaddtype/src/ops.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,13 @@ quad_heaviside(const Sleef_quad *x1, const Sleef_quad *x2)
}
}

static inline Sleef_quad
quad_hypot(const Sleef_quad *x1, const Sleef_quad *x2)
{
// hypot(x1, x2) = sqrt(x1^2 + x2^2)
return Sleef_hypotq1_u05(*x1, *x2);
}

// Binary long double operations
typedef long double (*binary_op_longdouble_def)(const long double *, const long double *);
// Binary long double operations with 2 outputs (for divmod, modf, frexp)
Expand Down Expand Up @@ -1108,6 +1115,14 @@ ld_heaviside(const long double *x1, const long double *x2)
}
}

static inline long double
ld_hypot(const long double *x1, const long double *x2)
{
// hypot(x1, x2) = sqrt(x1^2 + x2^2)
// Use the standard library hypotl function
return hypotl(*x1, *x2);
}

// comparison quad functions
typedef npy_bool (*cmp_quad_def)(const Sleef_quad *, const Sleef_quad *);

Expand Down
3 changes: 3 additions & 0 deletions quaddtype/numpy_quaddtype/src/umath/binary_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,9 @@ init_quad_binary_ops(PyObject *numpy)
if (create_quad_binary_ufunc<quad_heaviside, ld_heaviside>(numpy, "heaviside") < 0) {
return -1;
}
if (create_quad_binary_ufunc<quad_hypot, ld_hypot>(numpy, "hypot") < 0) {
return -1;
}
if (create_quad_binary_2out_ufunc<quad_divmod, ld_divmod>(numpy, "divmod") < 0) {
return -1;
}
Expand Down
5 changes: 1 addition & 4 deletions quaddtype/release_tracker.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@
| heaviside |||
| conj |||
| conjugate |||
| heaviside |||
| conj | | |
| conjugate | | |
| exp |||
| exp2 |||
| log |||
Expand All @@ -50,7 +47,7 @@
| arccos ||_Need: basic tests + edge cases (NaN/inf/±1/out-of-domain)_ |
| arctan ||_Need: basic tests + edge cases (NaN/inf/0/asymptotes)_ |
| arctan2 ||_Need: basic tests + edge cases (NaN/inf/0/quadrant coverage)_ |
| hypot | | |
| hypot | | |
| sinh |||
| cosh |||
| tanh |||
Expand Down
46 changes: 46 additions & 0 deletions quaddtype/tests/test_quaddtype.py
Original file line number Diff line number Diff line change
Expand Up @@ -1859,3 +1859,49 @@ def test_conj_conjugate_identity(func, value):
else:
assert result == x


@pytest.mark.parametrize("x1,x2,expected", [
# Basic Pythagorean triples
(3.0, 4.0, 5.0),
(5.0, 12.0, 13.0),
# Zero cases
(0.0, 0.0, 0.0),
(0.0, 5.0, 5.0),
(5.0, 0.0, 5.0),
# Negative values (hypot uses absolute values)
(-3.0, -4.0, 5.0),
(-3.0, 4.0, 5.0),
(3.0, -4.0, 5.0),
# Symmetry
(3.14159265358979323846, 2.71828182845904523536, None), # Will test symmetry
(2.71828182845904523536, 3.14159265358979323846, None), # Will test symmetry
# Infinity cases
(np.inf, 0.0, np.inf),
(0.0, np.inf, np.inf),
(np.inf, np.inf, np.inf),
(-np.inf, 0.0, np.inf),
(np.inf, -np.inf, np.inf),
# NaN cases
(np.nan, 3.0, np.nan),
(3.0, np.nan, np.nan),
(np.nan, np.nan, np.nan),
])
def test_hypot(x1, x2, expected):
"""Test hypot ufunc with various edge cases"""
q1 = QuadPrecision(x1)
q2 = QuadPrecision(x2)
result = np.hypot(q1, q2)

assert isinstance(result, QuadPrecision)

if expected is None:
# Symmetry test - just check the values are equal
result_reverse = np.hypot(q2, q1)
assert result == result_reverse
elif np.isnan(expected):
assert np.isnan(float(result))
elif np.isinf(expected):
assert np.isinf(float(result))
else:
np.testing.assert_allclose(float(result), expected, rtol=1e-13)

Loading