@@ -100,9 +100,9 @@ def test_array_minmax(op, a, b):
100100 np .testing .assert_array_equal (quad_res .astype (float ), float_res )
101101
102102 # Check sign for zero results
103- if float_result == 0.0 :
104- assert np .signbit (float_result ) == np .signbit (
105- quad_result ), f"Zero sign mismatch for { op } ({ a } , { b } )"
103+ if float_res == 0.0 :
104+ assert np .signbit (float_res ) == np .signbit (
105+ quad_res ), f"Zero sign mismatch for { op } ({ a } , { b } )"
106106
107107
108108@pytest .mark .parametrize ("op" , ["amin" , "amax" , "nanmin" , "nanmax" ])
@@ -119,9 +119,9 @@ def test_array_aminmax(op, a, b):
119119 np .testing .assert_array_equal (np .array (quad_res ).astype (float ), float_res )
120120
121121 # Check sign for zero results
122- if float_result == 0.0 :
123- assert np .signbit (float_result ) == np .signbit (
124- quad_result ), f"Zero sign mismatch for { op } ({ a } , { b } )"
122+ if float_res == 0.0 :
123+ assert np .signbit (float_res ) == np .signbit (
124+ quad_res ), f"Zero sign mismatch for { op } ({ a } , { b } )"
125125
126126
127127@pytest .mark .parametrize ("op" , ["negative" , "positive" , "absolute" , "sign" , "signbit" , "isfinite" , "isinf" , "isnan" , "sqrt" , "square" , "reciprocal" ])
@@ -478,3 +478,58 @@ def test_mod(a, b, backend, op):
478478 numpy_negative = numpy_result < 0
479479
480480 assert result_negative == numpy_negative , f"Sign mismatch for { a } % { b } : quad={ result_negative } , numpy={ numpy_negative } "
481+
482+
483+ @pytest .mark .parametrize ("op" , ["sinh" , "cosh" , "tanh" , "arcsinh" , "arccosh" , "arctanh" ])
484+ @pytest .mark .parametrize ("val" , [
485+ # Basic cases
486+ "0.0" , "-0.0" , "1.0" , "-1.0" , "2.0" , "-2.0" ,
487+ # Small values
488+ "1e-10" , "-1e-10" , "1e-15" , "-1e-15" ,
489+ # Values near one
490+ "0.9" , "-0.9" , "0.9999" , "-0.9999" ,
491+ "1.1" , "-1.1" , "1.0001" , "-1.0001" ,
492+ # Medium values
493+ "10.0" , "-10.0" , "20.0" , "-20.0" ,
494+ # Large values
495+ "100.0" , "200.0" , "700.0" , "1000.0" ,
496+ "-100.0" , "-200.0" , "-700.0" , "-1000.0" ,
497+ # Fractional values
498+ "0.5" , "-0.5" , "1.5" , "-1.5" , "2.5" , "-2.5" ,
499+ # Special values
500+ "inf" , "-inf" , "nan" , "-nan"
501+ ])
502+ def test_hyperbolic_functions (op , val ):
503+ """Comprehensive test for hyperbolic functions: sinh, cosh, tanh, arcsinh, arccosh, arctanh"""
504+ op_func = getattr (np , op )
505+
506+ quad_val = QuadPrecision (val )
507+ float_val = float (val )
508+
509+ quad_result = op_func (quad_val )
510+ float_result = op_func (float_val )
511+
512+ # Handle NaN cases
513+ if np .isnan (float_result ):
514+ assert np .isnan (
515+ float (quad_result )), f"Expected NaN for { op } ({ val } ), got { float (quad_result )} "
516+ return
517+
518+ # Handle infinity cases
519+ if np .isinf (float_result ):
520+ assert np .isinf (
521+ float (quad_result )), f"Expected inf for { op } ({ val } ), got { float (quad_result )} "
522+ assert np .sign (float_result ) == np .sign (
523+ float (quad_result )), f"Infinity sign mismatch for { op } ({ val } )"
524+ return
525+
526+ # For finite non-zero results
527+ # Use relative tolerance for exponential functions due to their rapid growth
528+ rtol = 1e-14 if abs (float_result ) < 1e100 else 1e-10
529+ np .testing .assert_allclose (float (quad_result ), float_result , rtol = rtol , atol = 1e-15 ,
530+ err_msg = f"Value mismatch for { op } ({ val } )" )
531+
532+ # Check sign for zero results
533+ if float_result == 0.0 :
534+ assert np .signbit (float_result ) == np .signbit (
535+ quad_result ), f"Zero sign mismatch for { op } ({ val } )"
0 commit comments