Unverified Commit 4ae338ff authored by Luca Ciucci's avatar Luca Ciucci Committed by GitHub
Browse files

APFloat: fix wrong result status for large floats (#189925)

For large float literals such as
`10384593717069655257060992658440193.0`,
[`FloatingLiteral::isExact`](https://github.com/llvm/llvm-project/blob/6b2b0da40de1495ace2b100799a35711f7ad7b21/clang/include/clang/AST/Expr.h#L1702)
was incorrectly returning `true`.

The issue has been tracked down to
`IEEEFloat::roundSignificandWithExponent` incorrectly reporting `opOK`.
parent 4f40fe10
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -2856,7 +2856,6 @@ IEEEFloat::roundSignificandWithExponent(const integerPart *decSigParts,
  unsigned pow5PartCount = powerOf5(pow5Parts, exp >= 0 ? exp : -exp);

  for (;; parts *= 2) {
    opStatus sigStatus, powStatus;
    unsigned int excessPrecision, truncatedBits;

    calcSemantics.precision = parts * integerPartWidth - 1;
@@ -2867,9 +2866,9 @@ IEEEFloat::roundSignificandWithExponent(const integerPart *decSigParts,
    decSig.makeZero(sign);
    IEEEFloat pow5(calcSemantics);

    sigStatus = decSig.convertFromUnsignedParts(decSigParts, sigPartCount,
                                                rmNearestTiesToEven);
    powStatus = pow5.convertFromUnsignedParts(pow5Parts, pow5PartCount,
    opStatus sigStatus = decSig.convertFromUnsignedParts(
        decSigParts, sigPartCount, rmNearestTiesToEven);
    opStatus powStatus = pow5.convertFromUnsignedParts(pow5Parts, pow5PartCount,
                                                       rmNearestTiesToEven);
    /* Add exp, as 10^n = 5^n * 2^n.  */
    decSig.exponent += exp;
@@ -2917,7 +2916,8 @@ IEEEFloat::roundSignificandWithExponent(const integerPart *decSigParts,
      calcLostFraction = lostFractionThroughTruncation(decSig.significandParts(),
                                                       decSig.partCount(),
                                                       truncatedBits);
      return normalize(rounding_mode, calcLostFraction);
      return static_cast<opStatus>(normalize(rounding_mode, calcLostFraction) |
                                   ((sigStatus | powStatus) & opInexact));
    }
  }
}
+22 −0
Original line number Diff line number Diff line
@@ -10206,4 +10206,26 @@ TEST(APFloatTest, isValidArbitraryFPFormat) {
  EXPECT_FALSE(APFloat::isValidArbitraryFPFormat("unknown"));
}

TEST(APFloatTest, DecimalStringPreservesInexactStatus) {
  APFloat F(APFloat::IEEEsingle());

  auto StatusOr = F.convertFromString("10384593717069655257060992658440193.0",
                                      APFloat::rmNearestTiesToEven);
  EXPECT_TRUE(!!StatusOr);

  APFloat::opStatus Status = *StatusOr;

  // The value is 2^113 + 1, not exactly representable in float.
  EXPECT_TRUE(Status & APFloat::opInexact);

  // But it should round to exactly 2^113.
  APFloat Expected(APFloat::IEEEsingle());
  auto ExpectedStatus =
      Expected.convertFromString("0x1p113", APFloat::rmNearestTiesToEven);
  EXPECT_TRUE(!!ExpectedStatus);
  EXPECT_FALSE(*ExpectedStatus & APFloat::opInexact);

  EXPECT_EQ(F.bitcastToAPInt(), Expected.bitcastToAPInt());
}

} // namespace