@@ -560,6 +560,81 @@ TEST(APFloatTest, FMA) {
560
560
EXPECT_EQ(-8.85242279E-41f, f1.convertToFloat());
561
561
}
562
562
563
+ // The `addOrSubtractSignificand` can be considered to have 9 possible cases
564
+ // when subtracting: all combinations of {cmpLessThan, cmpGreaterThan,
565
+ // cmpEqual} and {no loss, loss from lhs, loss from rhs}. Test each reachable
566
+ // case here.
567
+
568
+ // Regression test for failing the `assert(!carry)` in
569
+ // `addOrSubtractSignificand` and normalizing the exponent even when the
570
+ // significand is zero if there is a lost fraction.
571
+ // This tests cmpEqual, loss from lhs
572
+ {
573
+ APFloat f1(-1.4728589E-38f);
574
+ APFloat f2(3.7105144E-6f);
575
+ APFloat f3(5.5E-44f);
576
+ f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven);
577
+ EXPECT_EQ(-0.0f, f1.convertToFloat());
578
+ }
579
+
580
+ // Test cmpGreaterThan, no loss
581
+ {
582
+ APFloat f1(2.0f);
583
+ APFloat f2(2.0f);
584
+ APFloat f3(-3.5f);
585
+ f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven);
586
+ EXPECT_EQ(0.5f, f1.convertToFloat());
587
+ }
588
+
589
+ // Test cmpLessThan, no loss
590
+ {
591
+ APFloat f1(2.0f);
592
+ APFloat f2(2.0f);
593
+ APFloat f3(-4.5f);
594
+ f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven);
595
+ EXPECT_EQ(-0.5f, f1.convertToFloat());
596
+ }
597
+
598
+ // Test cmpEqual, no loss
599
+ {
600
+ APFloat f1(2.0f);
601
+ APFloat f2(2.0f);
602
+ APFloat f3(-4.0f);
603
+ f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven);
604
+ EXPECT_EQ(0.0f, f1.convertToFloat());
605
+ }
606
+
607
+ // Test cmpLessThan, loss from lhs
608
+ {
609
+ APFloat f1(2.0000002f);
610
+ APFloat f2(2.0000002f);
611
+ APFloat f3(-32.0f);
612
+ f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven);
613
+ EXPECT_EQ(-27.999998f, f1.convertToFloat());
614
+ }
615
+
616
+ // Test cmpGreaterThan, loss from rhs
617
+ {
618
+ APFloat f1(1e10f);
619
+ APFloat f2(1e10f);
620
+ APFloat f3(-2.0000002f);
621
+ f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven);
622
+ EXPECT_EQ(1e20f, f1.convertToFloat());
623
+ }
624
+
625
+ // Test cmpGreaterThan, loss from lhs
626
+ {
627
+ APFloat f1(1e-36f);
628
+ APFloat f2(0.0019531252f);
629
+ APFloat f3(-1e-45f);
630
+ f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven);
631
+ EXPECT_EQ(1.953124e-39f, f1.convertToFloat());
632
+ }
633
+
634
+ // {cmpEqual, cmpLessThan} with loss from rhs can't occur for the usage in
635
+ // `fusedMultiplyAdd` as `multiplySignificand` normalises the MSB of lhs to
636
+ // one bit below the top.
637
+
563
638
// Test using only a single instance of APFloat.
564
639
{
565
640
APFloat F(1.5);
@@ -7440,4 +7515,79 @@ TEST(APFloatTest, Float4E2M1FNToFloat) {
7440
7515
EXPECT_TRUE(SmallestDenorm.isDenormal());
7441
7516
EXPECT_EQ(0x0.8p0, SmallestDenorm.convertToFloat());
7442
7517
}
7518
+
7519
+ TEST(APFloatTest, AddOrSubtractSignificand) {
7520
+ class TestIEEEFloat : detail::IEEEFloat {
7521
+ TestIEEEFloat(bool sign, ExponentType exponent, integerPart significand)
7522
+ : detail::IEEEFloat(1.0) {
7523
+ // `addOrSubtractSignificand` only uses the sign, exponent and significand
7524
+ this->sign = sign;
7525
+ this->exponent = exponent;
7526
+ this->significand.part = significand;
7527
+ }
7528
+
7529
+ public:
7530
+ static void runTest(bool subtract, bool lhsSign, ExponentType lhsExponent,
7531
+ integerPart lhsSignificand, bool rhsSign,
7532
+ ExponentType rhsExponent, integerPart rhsSignificand,
7533
+ bool expectedSign, ExponentType expectedExponent,
7534
+ integerPart expectedSignificand,
7535
+ lostFraction expectedLoss) {
7536
+ TestIEEEFloat lhs(lhsSign, lhsExponent, lhsSignificand);
7537
+ TestIEEEFloat rhs(rhsSign, rhsExponent, rhsSignificand);
7538
+ lostFraction resultLoss = lhs.addOrSubtractSignificand(rhs, subtract);
7539
+ EXPECT_EQ(resultLoss, expectedLoss);
7540
+ EXPECT_EQ(lhs.sign, expectedSign);
7541
+ EXPECT_EQ(lhs.exponent, expectedExponent);
7542
+ EXPECT_EQ(lhs.significand.part, expectedSignificand);
7543
+ }
7544
+ };
7545
+
7546
+ // Test cases are all combinations of:
7547
+ // {equal exponents, LHS larger exponent, RHS larger exponent}
7548
+ // {equal significands, LHS larger significand, RHS larger significand}
7549
+ // {no loss, loss}
7550
+
7551
+ // Equal exponents (loss cannot occur as their is no shifting)
7552
+ TestIEEEFloat::runTest(true, false, 1, 0x10, false, 1, 0x5, false, 1, 0xb,
7553
+ lfExactlyZero);
7554
+ TestIEEEFloat::runTest(false, false, -2, 0x20, true, -2, 0x20, false, -2, 0,
7555
+ lfExactlyZero);
7556
+ TestIEEEFloat::runTest(false, true, 3, 0x20, false, 3, 0x30, false, 3, 0x10,
7557
+ lfExactlyZero);
7558
+
7559
+ // LHS larger exponent
7560
+ // LHS significand greater after shitfing
7561
+ TestIEEEFloat::runTest(true, false, 7, 0x100, false, 3, 0x100, false, 6,
7562
+ 0x1e0, lfExactlyZero);
7563
+ TestIEEEFloat::runTest(true, false, 7, 0x100, false, 3, 0x101, false, 6,
7564
+ 0x1df, lfMoreThanHalf);
7565
+ // Significands equal after shitfing
7566
+ TestIEEEFloat::runTest(true, false, 7, 0x100, false, 3, 0x1000, false, 6, 0,
7567
+ lfExactlyZero);
7568
+ TestIEEEFloat::runTest(true, false, 7, 0x100, false, 3, 0x1001, true, 6, 0,
7569
+ lfLessThanHalf);
7570
+ // RHS significand greater after shitfing
7571
+ TestIEEEFloat::runTest(true, false, 7, 0x100, false, 3, 0x10000, true, 6,
7572
+ 0x1e00, lfExactlyZero);
7573
+ TestIEEEFloat::runTest(true, false, 7, 0x100, false, 3, 0x10001, true, 6,
7574
+ 0x1e00, lfLessThanHalf);
7575
+
7576
+ // RHS larger exponent
7577
+ // RHS significand greater after shitfing
7578
+ TestIEEEFloat::runTest(true, false, 3, 0x100, false, 7, 0x100, true, 6, 0x1e0,
7579
+ lfExactlyZero);
7580
+ TestIEEEFloat::runTest(true, false, 3, 0x101, false, 7, 0x100, true, 6, 0x1df,
7581
+ lfMoreThanHalf);
7582
+ // Significands equal after shitfing
7583
+ TestIEEEFloat::runTest(true, false, 3, 0x1000, false, 7, 0x100, false, 6, 0,
7584
+ lfExactlyZero);
7585
+ TestIEEEFloat::runTest(true, false, 3, 0x1001, false, 7, 0x100, false, 6, 0,
7586
+ lfLessThanHalf);
7587
+ // LHS significand greater after shitfing
7588
+ TestIEEEFloat::runTest(true, false, 3, 0x10000, false, 7, 0x100, false, 6,
7589
+ 0x1e00, lfExactlyZero);
7590
+ TestIEEEFloat::runTest(true, false, 3, 0x10001, false, 7, 0x100, false, 6,
7591
+ 0x1e00, lfLessThanHalf);
7592
+ }
7443
7593
} // namespace
0 commit comments