@@ -429,6 +429,75 @@ def test_log1p(val):
429429 quad_result ), f"Zero sign mismatch for { op } ({ val } )"
430430
431431
432+ @pytest .mark .parametrize ("val" , [
433+ # Cases close to 0 (where expm1 is most accurate and important)
434+ "0.0" , "-0.0" ,
435+ "1e-10" , "-1e-10" , "1e-15" , "-1e-15" , "1e-20" , "-1e-20" ,
436+ "1e-100" , "-1e-100" , "1e-300" , "-1e-300" ,
437+ # Small values
438+ "0.001" , "-0.001" , "0.01" , "-0.01" , "0.1" , "-0.1" ,
439+ # Moderate values
440+ "0.5" , "-0.5" , "1.0" , "-1.0" , "2.0" , "-2.0" ,
441+ # Larger values
442+ "5.0" , "-5.0" , "10.0" , "-10.0" , "20.0" , "-20.0" ,
443+ # Values that test exp behavior
444+ "50.0" , "-50.0" , "100.0" , "-100.0" ,
445+ # Large positive values (exp(x) grows rapidly)
446+ "200.0" , "500.0" , "700.0" ,
447+ # Large negative values (should approach -1)
448+ "-200.0" , "-500.0" , "-700.0" , "-1000.0" ,
449+ # Special values
450+ "inf" , # Should give inf
451+ "-inf" , # Should give -1
452+ "nan" , "-nan"
453+ ])
454+ def test_expm1 (val ):
455+ """Comprehensive test for expm1 function: exp(x) - 1
456+
457+ This function provides greater precision than exp(x) - 1 for small values of x.
458+ """
459+ quad_val = QuadPrecision (val )
460+ float_val = float (val )
461+
462+ quad_result = np .expm1 (quad_val )
463+ float_result = np .expm1 (float_val )
464+
465+ # Handle NaN cases
466+ if np .isnan (float_result ):
467+ assert np .isnan (
468+ float (quad_result )), f"Expected NaN for expm1({ val } ), got { float (quad_result )} "
469+ return
470+
471+ # Handle infinity cases
472+ if np .isinf (float_result ):
473+ assert np .isinf (
474+ float (quad_result )), f"Expected inf for expm1({ val } ), got { float (quad_result )} "
475+ assert np .sign (float_result ) == np .sign (
476+ float (quad_result )), f"Infinity sign mismatch for expm1({ val } )"
477+ return
478+
479+ # For finite results
480+ # expm1 is designed for high accuracy near 0, so use tight tolerances for small inputs
481+ if abs (float (val )) < 1e-10 :
482+ rtol = 1e-15
483+ atol = 1e-20
484+ elif abs (float_result ) < 1 :
485+ rtol = 1e-14
486+ atol = 1e-15
487+ else :
488+ # For larger results, use relative tolerance
489+ rtol = 1e-14
490+ atol = 1e-15
491+
492+ np .testing .assert_allclose (float (quad_result ), float_result , rtol = rtol , atol = atol ,
493+ err_msg = f"Value mismatch for expm1({ val } )" )
494+
495+ # Check sign for zero results
496+ if float_result == 0.0 :
497+ assert np .signbit (float_result ) == np .signbit (
498+ quad_result ), f"Zero sign mismatch for expm1({ val } )"
499+
500+
432501@pytest .mark .parametrize ("x" , [
433502 # Regular values
434503 "0.0" , "1.0" , "2.0" , "-1.0" , "-2.0" , "0.5" , "-0.5" ,
0 commit comments