@@ -367,7 +367,7 @@ def test_logarithmic_functions(op, val):
367367 # Check sign for zero results
368368 if float_result == 0.0 :
369369 assert np .signbit (float_result ) == np .signbit (
370- quad_result ), f"Zero sign mismatch for { op } ( { a } , { b } ) "
370+ quad_result ), f"Zero sign mismatch"
371371
372372
373373@pytest .mark .parametrize ("val" , [
@@ -390,6 +390,7 @@ def test_logarithmic_functions(op, val):
390390])
391391def test_log1p (val ):
392392 """Comprehensive test for log1p function"""
393+ op = "log1p"
393394 quad_val = QuadPrecision (val )
394395 float_val = float (val )
395396
@@ -427,6 +428,106 @@ def test_log1p(val):
427428 assert np .signbit (float_result ) == np .signbit (
428429 quad_result ), f"Zero sign mismatch for { op } ({ val } )"
429430
431+
432+ @pytest .mark .parametrize ("x" , [
433+ # Regular values
434+ "0.0" , "1.0" , "2.0" , "-1.0" , "-2.0" , "0.5" , "-0.5" ,
435+ # Large values (test numerical stability)
436+ "100.0" , "1000.0" , "-100.0" , "-1000.0" ,
437+ # Small values
438+ "1e-10" , "-1e-10" , "1e-20" , "-1e-20" ,
439+ # Special values
440+ "inf" , "-inf" , "nan" , "-nan" , "-0.0"
441+ ])
442+ @pytest .mark .parametrize ("y" , [
443+ # Regular values
444+ "0.0" , "1.0" , "2.0" , "-1.0" , "-2.0" , "0.5" , "-0.5" ,
445+ # Large values
446+ "100.0" , "1000.0" , "-100.0" , "-1000.0" ,
447+ # Small values
448+ "1e-10" , "-1e-10" , "1e-20" , "-1e-20" ,
449+ # Special values
450+ "inf" , "-inf" , "nan" , "-nan" , "-0.0"
451+ ])
452+ def test_logaddexp (x , y ):
453+ """Comprehensive test for logaddexp function: log(exp(x) + exp(y))"""
454+ quad_x = QuadPrecision (x )
455+ quad_y = QuadPrecision (y )
456+ float_x = float (x )
457+ float_y = float (y )
458+
459+ quad_result = np .logaddexp (quad_x , quad_y )
460+ float_result = np .logaddexp (float_x , float_y )
461+
462+ # Handle NaN cases
463+ if np .isnan (float_result ):
464+ assert np .isnan (float (quad_result )), \
465+ f"Expected NaN for logaddexp({ x } , { y } ), got { float (quad_result )} "
466+ return
467+
468+ # Handle infinity cases
469+ if np .isinf (float_result ):
470+ assert np .isinf (float (quad_result )), \
471+ f"Expected inf for logaddexp({ x } , { y } ), got { float (quad_result )} "
472+ if not np .isnan (float_result ):
473+ assert np .sign (float_result ) == np .sign (float (quad_result )), \
474+ f"Infinity sign mismatch for logaddexp({ x } , { y } )"
475+ return
476+
477+ # For finite results, check with appropriate tolerance
478+ # logaddexp is numerically sensitive, especially for large differences
479+ if abs (float_x - float_y ) > 50 :
480+ # When values differ greatly, result should be close to max(x, y)
481+ rtol = 1e-10
482+ atol = 1e-10
483+ else :
484+ rtol = 1e-13
485+ atol = 1e-15
486+
487+ np .testing .assert_allclose (
488+ float (quad_result ), float_result ,
489+ rtol = rtol , atol = atol ,
490+ err_msg = f"Value mismatch for logaddexp({ x } , { y } )"
491+ )
492+
493+
494+ def test_logaddexp_special_properties ():
495+ """Test special mathematical properties of logaddexp"""
496+ # logaddexp(x, x) = x + log(2)
497+ x = QuadPrecision ("2.0" )
498+ result = np .logaddexp (x , x )
499+ expected = float (x ) + np .log (2.0 )
500+ np .testing .assert_allclose (float (result ), expected , rtol = 1e-14 )
501+
502+ # logaddexp(x, -inf) = x
503+ x = QuadPrecision ("5.0" )
504+ result = np .logaddexp (x , QuadPrecision ("-inf" ))
505+ np .testing .assert_allclose (float (result ), float (x ), rtol = 1e-14 )
506+
507+ # logaddexp(-inf, x) = x
508+ result = np .logaddexp (QuadPrecision ("-inf" ), x )
509+ np .testing .assert_allclose (float (result ), float (x ), rtol = 1e-14 )
510+
511+ # logaddexp(-inf, -inf) = -inf
512+ result = np .logaddexp (QuadPrecision ("-inf" ), QuadPrecision ("-inf" ))
513+ assert np .isinf (float (result )) and float (result ) < 0
514+
515+ # logaddexp(inf, anything) = inf
516+ result = np .logaddexp (QuadPrecision ("inf" ), QuadPrecision ("100.0" ))
517+ assert np .isinf (float (result )) and float (result ) > 0
518+
519+ # logaddexp(anything, inf) = inf
520+ result = np .logaddexp (QuadPrecision ("100.0" ), QuadPrecision ("inf" ))
521+ assert np .isinf (float (result )) and float (result ) > 0
522+
523+ # Commutativity: logaddexp(x, y) = logaddexp(y, x)
524+ x = QuadPrecision ("3.0" )
525+ y = QuadPrecision ("5.0" )
526+ result1 = np .logaddexp (x , y )
527+ result2 = np .logaddexp (y , x )
528+ np .testing .assert_allclose (float (result1 ), float (result2 ), rtol = 1e-14 )
529+
530+
430531def test_inf ():
431532 assert QuadPrecision ("inf" ) > QuadPrecision ("1e1000" )
432533 assert np .signbit (QuadPrecision ("inf" )) == 0
0 commit comments