@@ -528,6 +528,210 @@ def test_logaddexp_special_properties():
528528 np .testing .assert_allclose (float (result1 ), float (result2 ), rtol = 1e-14 )
529529
530530
531+ @pytest .mark .parametrize ("x" , [
532+ # Regular values
533+ "0.0" , "1.0" , "2.0" , "-1.0" , "-2.0" , "0.5" , "-0.5" ,
534+ # Large values (test numerical stability)
535+ "100.0" , "1000.0" , "-100.0" , "-1000.0" ,
536+ # Small values
537+ "1e-10" , "-1e-10" , "1e-20" , "-1e-20" ,
538+ # Special values
539+ "inf" , "-inf" , "nan" , "-nan" , "-0.0"
540+ ])
541+ @pytest .mark .parametrize ("y" , [
542+ # Regular values
543+ "0.0" , "1.0" , "2.0" , "-1.0" , "-2.0" , "0.5" , "-0.5" ,
544+ # Large values
545+ "100.0" , "1000.0" , "-100.0" , "-1000.0" ,
546+ # Small values
547+ "1e-10" , "-1e-10" , "1e-20" , "-1e-20" ,
548+ # Special values
549+ "inf" , "-inf" , "nan" , "-nan" , "-0.0"
550+ ])
551+ def test_logaddexp2 (x , y ):
552+ """Comprehensive test for logaddexp2 function: log2(2^x + 2^y)"""
553+ quad_x = QuadPrecision (x )
554+ quad_y = QuadPrecision (y )
555+ float_x = float (x )
556+ float_y = float (y )
557+
558+ quad_result = np .logaddexp2 (quad_x , quad_y )
559+ float_result = np .logaddexp2 (float_x , float_y )
560+
561+ # Handle NaN cases
562+ if np .isnan (float_result ):
563+ assert np .isnan (float (quad_result )), \
564+ f"Expected NaN for logaddexp2({ x } , { y } ), got { float (quad_result )} "
565+ return
566+
567+ # Handle infinity cases
568+ if np .isinf (float_result ):
569+ assert np .isinf (float (quad_result )), \
570+ f"Expected inf for logaddexp2({ x } , { y } ), got { float (quad_result )} "
571+ if not np .isnan (float_result ):
572+ assert np .sign (float_result ) == np .sign (float (quad_result )), \
573+ f"Infinity sign mismatch for logaddexp2({ x } , { y } )"
574+ return
575+
576+ # For finite results, check with appropriate tolerance
577+ # logaddexp2 is numerically sensitive, especially for large differences
578+ if abs (float_x - float_y ) > 50 :
579+ # When values differ greatly, result should be close to max(x, y)
580+ rtol = 1e-10
581+ atol = 1e-10
582+ else :
583+ rtol = 1e-13
584+ atol = 1e-15
585+
586+ np .testing .assert_allclose (
587+ float (quad_result ), float_result ,
588+ rtol = rtol , atol = atol ,
589+ err_msg = f"Value mismatch for logaddexp2({ x } , { y } )"
590+ )
591+
592+
593+ def test_logaddexp2_special_properties ():
594+ """Test special mathematical properties of logaddexp2"""
595+ # logaddexp2(x, x) = x + 1 (since log2(2^x + 2^x) = log2(2 * 2^x) = log2(2) + log2(2^x) = 1 + x)
596+ x = QuadPrecision ("2.0" )
597+ result = np .logaddexp2 (x , x )
598+ expected = float (x ) + 1.0
599+ np .testing .assert_allclose (float (result ), expected , rtol = 1e-14 )
600+
601+ # logaddexp2(x, -inf) = x
602+ x = QuadPrecision ("5.0" )
603+ result = np .logaddexp2 (x , QuadPrecision ("-inf" ))
604+ np .testing .assert_allclose (float (result ), float (x ), rtol = 1e-14 )
605+
606+ # logaddexp2(-inf, x) = x
607+ result = np .logaddexp2 (QuadPrecision ("-inf" ), x )
608+ np .testing .assert_allclose (float (result ), float (x ), rtol = 1e-14 )
609+
610+ # logaddexp2(-inf, -inf) = -inf
611+ result = np .logaddexp2 (QuadPrecision ("-inf" ), QuadPrecision ("-inf" ))
612+ assert np .isinf (float (result )) and float (result ) < 0
613+
614+ # logaddexp2(inf, anything) = inf
615+ result = np .logaddexp2 (QuadPrecision ("inf" ), QuadPrecision ("100.0" ))
616+ assert np .isinf (float (result )) and float (result ) > 0
617+
618+ # logaddexp2(anything, inf) = inf
619+ result = np .logaddexp2 (QuadPrecision ("100.0" ), QuadPrecision ("inf" ))
620+ assert np .isinf (float (result )) and float (result ) > 0
621+
622+ # Commutativity: logaddexp2(x, y) = logaddexp2(y, x)
623+ x = QuadPrecision ("3.0" )
624+ y = QuadPrecision ("5.0" )
625+ result1 = np .logaddexp2 (x , y )
626+ result2 = np .logaddexp2 (y , x )
627+ np .testing .assert_allclose (float (result1 ), float (result2 ), rtol = 1e-14 )
628+
629+ # Relationship with logaddexp: logaddexp2(x, y) = logaddexp(x*ln2, y*ln2) / ln2
630+ x = QuadPrecision ("2.0" )
631+ y = QuadPrecision ("3.0" )
632+ result_logaddexp2 = np .logaddexp2 (x , y )
633+ ln2 = np .log (2.0 )
634+ result_logaddexp = np .logaddexp (float (x ) * ln2 , float (y ) * ln2 ) / ln2
635+ np .testing .assert_allclose (float (result_logaddexp2 ), result_logaddexp , rtol = 1e-13 )
636+
637+
638+ @pytest .mark .parametrize (
639+ "x_val" ,
640+ [
641+ 0.0 , 1.0 , 2.0 , - 1.0 , - 2.0 ,
642+ 0.5 , - 0.5 ,
643+ 100.0 , 1000.0 , - 100.0 , - 1000.0 ,
644+ 1e-10 , - 1e-10 , 1e-20 , - 1e-20 ,
645+ float ("inf" ), float ("-inf" ), float ("nan" ), float ("-nan" ), - 0.0
646+ ]
647+ )
648+ @pytest .mark .parametrize (
649+ "y_val" ,
650+ [
651+ 0.0 , 1.0 , 2.0 , - 1.0 , - 2.0 ,
652+ 0.5 , - 0.5 ,
653+ 100.0 , 1000.0 , - 100.0 , - 1000.0 ,
654+ 1e-10 , - 1e-10 , 1e-20 , - 1e-20 ,
655+ float ("inf" ), float ("-inf" ), float ("nan" ), float ("-nan" ), - 0.0
656+ ]
657+ )
658+ def test_true_divide (x_val , y_val ):
659+ """Test true_divide ufunc with comprehensive edge cases"""
660+ x_quad = QuadPrecision (str (x_val ))
661+ y_quad = QuadPrecision (str (y_val ))
662+
663+ # Compute using QuadPrecision
664+ result_quad = np .true_divide (x_quad , y_quad )
665+
666+ # Compute using float64 for comparison
667+ result_float64 = np .true_divide (np .float64 (x_val ), np .float64 (y_val ))
668+
669+ # Compare results
670+ if np .isnan (result_float64 ):
671+ assert np .isnan (float (result_quad )), f"Expected NaN for true_divide({ x_val } , { y_val } )"
672+ elif np .isinf (result_float64 ):
673+ assert np .isinf (float (result_quad )), f"Expected inf for true_divide({ x_val } , { y_val } )"
674+ assert np .sign (float (result_quad )) == np .sign (result_float64 ), f"Sign mismatch for true_divide({ x_val } , { y_val } )"
675+ else :
676+ # For finite results, check relative tolerance
677+ np .testing .assert_allclose (
678+ float (result_quad ), result_float64 , rtol = 1e-14 ,
679+ err_msg = f"Mismatch for true_divide({ x_val } , { y_val } )"
680+ )
681+
682+
683+ def test_true_divide_special_properties ():
684+ """Test special mathematical properties of true_divide"""
685+ # Division by 1 returns the original value
686+ x = QuadPrecision ("42.123456789" )
687+ result = np .true_divide (x , QuadPrecision ("1.0" ))
688+ np .testing .assert_allclose (float (result ), float (x ), rtol = 1e-30 )
689+
690+ # Division of 0 by any non-zero number is 0
691+ result = np .true_divide (QuadPrecision ("0.0" ), QuadPrecision ("5.0" ))
692+ assert float (result ) == 0.0
693+
694+ # Division by 0 gives inf (with appropriate sign)
695+ result = np .true_divide (QuadPrecision ("1.0" ), QuadPrecision ("0.0" ))
696+ assert np .isinf (float (result )) and float (result ) > 0
697+
698+ result = np .true_divide (QuadPrecision ("-1.0" ), QuadPrecision ("0.0" ))
699+ assert np .isinf (float (result )) and float (result ) < 0
700+
701+ # 0 / 0 = NaN
702+ result = np .true_divide (QuadPrecision ("0.0" ), QuadPrecision ("0.0" ))
703+ assert np .isnan (float (result ))
704+
705+ # inf / inf = NaN
706+ result = np .true_divide (QuadPrecision ("inf" ), QuadPrecision ("inf" ))
707+ assert np .isnan (float (result ))
708+
709+ # inf / finite = inf
710+ result = np .true_divide (QuadPrecision ("inf" ), QuadPrecision ("100.0" ))
711+ assert np .isinf (float (result )) and float (result ) > 0
712+
713+ # finite / inf = 0
714+ result = np .true_divide (QuadPrecision ("100.0" ), QuadPrecision ("inf" ))
715+ assert float (result ) == 0.0
716+
717+ # Self-division (x / x) = 1 for finite non-zero x
718+ x = QuadPrecision ("7.123456789" )
719+ result = np .true_divide (x , x )
720+ np .testing .assert_allclose (float (result ), 1.0 , rtol = 1e-30 )
721+
722+ # Sign preservation: (-x) / y = -(x / y)
723+ x = QuadPrecision ("5.5" )
724+ y = QuadPrecision ("2.2" )
725+ result1 = np .true_divide (- x , y )
726+ result2 = - np .true_divide (x , y )
727+ np .testing .assert_allclose (float (result1 ), float (result2 ), rtol = 1e-30 )
728+
729+ # Sign rule: negative / negative = positive
730+ result = np .true_divide (QuadPrecision ("-6.0" ), QuadPrecision ("-2.0" ))
731+ assert float (result ) > 0
732+ np .testing .assert_allclose (float (result ), 3.0 , rtol = 1e-30 )
733+
734+
531735def test_inf ():
532736 assert QuadPrecision ("inf" ) > QuadPrecision ("1e1000" )
533737 assert np .signbit (QuadPrecision ("inf" )) == 0
0 commit comments