diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h index a83563a5a6f..9e8642bfaed 100644 --- a/include/llvm/ADT/APFloat.h +++ b/include/llvm/ADT/APFloat.h @@ -491,6 +491,22 @@ public: /// return true. bool getExactInverse(APFloat *inv) const; + /// \brief Returns the exponent of the internal representation of the APFloat. + /// + /// Because the radix of APFloat is 2, this is equivalent to floor(log2(x)). + friend APFloat logb(const APFloat &Arg) { + if (Arg.isZero() || Arg.isNaN()) + return Arg; + + if (Arg.isInfinity()) + return APFloat::getInf(Arg.getSemantics()); + + APFloat Result(Arg.getSemantics(), std::abs(Arg.exponent)); + if (Arg.exponent < 0) + Result.changeSign(); + return Result; + } + private: /// \name Simple Queries @@ -617,6 +633,7 @@ private: /// This additional declaration is required in order to compile LLVM with IBM /// xlC compiler. hash_code hash_value(const APFloat &Arg); + } // namespace llvm #endif // LLVM_ADT_APFLOAT_H diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp index a4816efc214..8dd6f9f9931 100644 --- a/unittests/ADT/APFloatTest.cpp +++ b/unittests/ADT/APFloatTest.cpp @@ -2691,4 +2691,55 @@ TEST(APFloatTest, operatorOverloads) { EXPECT_TRUE(Two.bitwiseIsEqual(One * Two)); EXPECT_TRUE(One.bitwiseIsEqual(Two / Two)); } + +TEST(APFloatTest, logb) { + EXPECT_TRUE( + APFloat(APFloat::IEEEsingle, "0x0p+0") + .bitwiseIsEqual(logb(APFloat(APFloat::IEEEsingle, "0x1p+0")))); + EXPECT_TRUE( + APFloat(APFloat::IEEEsingle, "0x0p+0") + .bitwiseIsEqual(logb(APFloat(APFloat::IEEEsingle, "-0x1p+0")))); + EXPECT_TRUE( + APFloat(APFloat::IEEEsingle, "0x2Ap+0") + .bitwiseIsEqual(logb(APFloat(APFloat::IEEEsingle, "0x1p+42")))); + EXPECT_TRUE( + APFloat(APFloat::IEEEsingle, "-0x2Ap+0") + .bitwiseIsEqual(logb(APFloat(APFloat::IEEEsingle, "0x1p-42")))); + + APFloat PInf = APFloat::getInf(APFloat::IEEEsingle, false); + APFloat MInf = APFloat::getInf(APFloat::IEEEsingle, true); + APFloat PZero = APFloat::getZero(APFloat::IEEEsingle, false); + APFloat MZero = APFloat::getZero(APFloat::IEEEsingle, true); + APFloat QNaN = APFloat::getNaN(APFloat::IEEEsingle, false); + APFloat SNaN = APFloat::getSNaN(APFloat::IEEEsingle, false); + + EXPECT_TRUE(PInf.bitwiseIsEqual(logb(PInf))); + EXPECT_TRUE(PInf.bitwiseIsEqual(logb(MInf))); + EXPECT_TRUE(PZero.bitwiseIsEqual(logb(PZero))); + EXPECT_TRUE(MZero.bitwiseIsEqual(logb(MZero))); + EXPECT_TRUE(QNaN.bitwiseIsEqual(logb(QNaN))); + EXPECT_TRUE(SNaN.bitwiseIsEqual(logb(SNaN))); + + APFloat PLargestValue = APFloat::getLargest(APFloat::IEEEsingle, false); + APFloat MLargestValue = APFloat::getLargest(APFloat::IEEEsingle, true); + APFloat PSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle, false); + APFloat MSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle, true); + APFloat PSmallestNormalized = + APFloat::getSmallestNormalized(APFloat::IEEEsingle, false); + APFloat MSmallestNormalized = + APFloat::getSmallestNormalized(APFloat::IEEEsingle, true); + + EXPECT_TRUE( + APFloat(APFloat::IEEEsingle, "0x7Fp+0").bitwiseIsEqual(logb(PLargestValue))); + EXPECT_TRUE( + APFloat(APFloat::IEEEsingle, "0x7Fp+0").bitwiseIsEqual(logb(MLargestValue))); + EXPECT_TRUE( + APFloat(APFloat::IEEEsingle, "-0x7Ep+0").bitwiseIsEqual(logb(PSmallestValue))); + EXPECT_TRUE( + APFloat(APFloat::IEEEsingle, "-0x7Ep+0").bitwiseIsEqual(logb(MSmallestValue))); + EXPECT_TRUE(APFloat(APFloat::IEEEsingle, "-0x7Ep+0") + .bitwiseIsEqual(logb(PSmallestNormalized))); + EXPECT_TRUE(APFloat(APFloat::IEEEsingle, "-0x7Ep+0") + .bitwiseIsEqual(logb(MSmallestNormalized))); +} }