Index: include/llvm/ADT/APFloat.h =================================================================== --- include/llvm/ADT/APFloat.h +++ include/llvm/ADT/APFloat.h @@ -516,6 +516,8 @@ /// \brief Returns: X * 2^Exp for integral exponents. friend APFloat scalbn(APFloat X, int Exp, roundingMode); + friend APFloat frexp(const APFloat &X, int &Exp, roundingMode); + private: /// \name Simple Queries @@ -570,6 +572,7 @@ const APInt *fill); void makeInf(bool Neg = false); void makeZero(bool Neg = false); + void makeQuiet(); /// @} @@ -645,6 +648,12 @@ int ilogb(const APFloat &Arg); APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode); +/// \brief Equivalent of C standard library function. +/// +/// While the C standard says Exp is an unspecified value for infinity and nan, +/// this returns INT_MAX for infinities, and INT_MIN for NaNs. +APFloat frexp(const APFloat &Val, int &Exp, APFloat::roundingMode RM); + /// \brief Returns the absolute value of the argument. inline APFloat abs(APFloat X) { X.clearSign(); Index: lib/Support/APFloat.cpp =================================================================== --- lib/Support/APFloat.cpp +++ lib/Support/APFloat.cpp @@ -3942,7 +3942,12 @@ category = fcZero; sign = Negative; exponent = semantics->minExponent-1; - APInt::tcSet(significandParts(), 0, partCount()); + APInt::tcSet(significandParts(), 0, partCount()); +} + +void APFloat::makeQuiet() { + assert(isNaN()); + APInt::tcSetBit(significandParts(), semantics->precision - 2); } int llvm::ilogb(const APFloat &Arg) { @@ -3981,3 +3986,22 @@ X.normalize(RoundingMode, lfExactlyZero); return X; } + +APFloat llvm::frexp(const APFloat &Val, int &Exp, APFloat::roundingMode RM) { + Exp = ilogb(Val); + + // Quiet signalling nans. + if (Exp == APFloat::IEK_NaN) { + APFloat Quiet(Val); + Quiet.makeQuiet(); + return Quiet; + } + + if (Exp == APFloat::IEK_Inf) + return Val; + + // 1 is added because frexp is defined to return a normalized fraction in + // +/-[0.5, 1.0), rather than the usual +/-[1.0, 2.0). + Exp = Exp == APFloat::IEK_Zero ? 0 : Exp + 1; + return scalbn(Val, -Exp, RM); +} Index: unittests/ADT/APFloatTest.cpp =================================================================== --- unittests/ADT/APFloatTest.cpp +++ unittests/ADT/APFloatTest.cpp @@ -3017,5 +3017,135 @@ EXPECT_TRUE( APFloat(APFloat::IEEEdouble, "0x1p-103") .bitwiseIsEqual(scalbn(APFloat(APFloat::IEEEdouble, "0x1p-51"), -52, RM))); + + APFloat ScalbnSNaN = scalbn(SNaN, 0, RM); + EXPECT_TRUE(ScalbnSNaN.isNaN() && !ScalbnSNaN.isSignaling()); +} + +TEST(APFloatTest, frexp) { + const APFloat::roundingMode RM = APFloat::rmNearestTiesToEven; + + APFloat PZero = APFloat::getZero(APFloat::IEEEdouble, false); + APFloat MZero = APFloat::getZero(APFloat::IEEEdouble, true); + APFloat One(1.0); + APFloat MOne(-1.0); + APFloat Two(2.0); + APFloat MTwo(-2.0); + + APFloat LargestDenormal(APFloat::IEEEdouble, "0x1.ffffffffffffep-1023"); + APFloat NegLargestDenormal(APFloat::IEEEdouble, "-0x1.ffffffffffffep-1023"); + + APFloat Smallest = APFloat::getSmallest(APFloat::IEEEdouble, false); + APFloat NegSmallest = APFloat::getSmallest(APFloat::IEEEdouble, true); + + APFloat Largest = APFloat::getLargest(APFloat::IEEEdouble, false); + APFloat NegLargest = APFloat::getLargest(APFloat::IEEEdouble, true); + + APFloat PInf = APFloat::getInf(APFloat::IEEEdouble, false); + APFloat MInf = APFloat::getInf(APFloat::IEEEdouble, true); + + APFloat QPNaN = APFloat::getNaN(APFloat::IEEEdouble, false); + APFloat QMNaN = APFloat::getNaN(APFloat::IEEEdouble, true); + APFloat SNaN = APFloat::getSNaN(APFloat::IEEEdouble, false); + + // Make sure highest bit of payload is preserved. + const APInt Payload(64, (UINT64_C(1) << 50) | + (UINT64_C(1) << 49) | + (UINT64_C(1234) << 32) | + 1); + + APFloat SNaNWithPayload = APFloat::getSNaN(APFloat::IEEEdouble, false, + &Payload); + + APFloat SmallestNormalized + = APFloat::getSmallestNormalized(APFloat::IEEEdouble, false); + APFloat NegSmallestNormalized + = APFloat::getSmallestNormalized(APFloat::IEEEdouble, true); + + int Exp; + APFloat Frac(APFloat::IEEEdouble); + + + + Frac = frexp(PZero, Exp, RM); + EXPECT_EQ(0, Exp); + EXPECT_TRUE(Frac.isPosZero()); + + Frac = frexp(MZero, Exp, RM); + EXPECT_EQ(0, Exp); + EXPECT_TRUE(Frac.isNegZero()); + + + Frac = frexp(One, Exp, RM); + EXPECT_EQ(1, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1p-1").bitwiseIsEqual(Frac)); + + Frac = frexp(MOne, Exp, RM); + EXPECT_EQ(1, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-0x1p-1").bitwiseIsEqual(Frac)); + + Frac = frexp(LargestDenormal, Exp, RM); + EXPECT_EQ(-1022, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.ffffffffffffep-1").bitwiseIsEqual(Frac)); + + Frac = frexp(NegLargestDenormal, Exp, RM); + EXPECT_EQ(-1022, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-0x1.ffffffffffffep-1").bitwiseIsEqual(Frac)); + + + Frac = frexp(Smallest, Exp, RM); + EXPECT_EQ(-1073, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1p-1").bitwiseIsEqual(Frac)); + + Frac = frexp(NegSmallest, Exp, RM); + EXPECT_EQ(-1073, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-0x1p-1").bitwiseIsEqual(Frac)); + + + Frac = frexp(Largest, Exp, RM); + EXPECT_EQ(1024, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.fffffffffffffp-1").bitwiseIsEqual(Frac)); + + Frac = frexp(NegLargest, Exp, RM); + EXPECT_EQ(1024, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-0x1.fffffffffffffp-1").bitwiseIsEqual(Frac)); + + + Frac = frexp(PInf, Exp, RM); + EXPECT_EQ(INT_MAX, Exp); + EXPECT_TRUE(Frac.isInfinity() && !Frac.isNegative()); + + Frac = frexp(MInf, Exp, RM); + EXPECT_EQ(INT_MAX, Exp); + EXPECT_TRUE(Frac.isInfinity() && Frac.isNegative()); + + Frac = frexp(QPNaN, Exp, RM); + EXPECT_EQ(INT_MIN, Exp); + EXPECT_TRUE(Frac.isNaN()); + + Frac = frexp(QMNaN, Exp, RM); + EXPECT_EQ(INT_MIN, Exp); + EXPECT_TRUE(Frac.isNaN()); + + Frac = frexp(SNaN, Exp, RM); + EXPECT_EQ(INT_MIN, Exp); + EXPECT_TRUE(Frac.isNaN() && !Frac.isSignaling()); + + Frac = frexp(SNaNWithPayload, Exp, RM); + EXPECT_EQ(INT_MIN, Exp); + EXPECT_TRUE(Frac.isNaN() && !Frac.isSignaling()); + EXPECT_EQ(Payload, Frac.bitcastToAPInt().getLoBits(51)); + + Frac = frexp(APFloat(APFloat::IEEEdouble, "0x0.ffffp-1"), Exp, RM); + EXPECT_EQ(-1, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.fffep-1").bitwiseIsEqual(Frac)); + + Frac = frexp(APFloat(APFloat::IEEEdouble, "0x1p-51"), Exp, RM); + EXPECT_EQ(-50, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1p-1").bitwiseIsEqual(Frac)); + + Frac = frexp(APFloat(APFloat::IEEEdouble, "0x1.c60f120d9f87cp+51"), Exp, RM); + EXPECT_EQ(52, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.c60f120d9f87cp-1").bitwiseIsEqual(Frac)); } }