diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h index 9792749230cbf..a07f637b384a8 100644 --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -1536,6 +1536,26 @@ inline APFloat abs(APFloat X) { return X; } +/// Returns X^N for N >= 0. +inline APFloat powi(const APFloat &X, int64_t N) { + APFloat Acc = APFloat::getOne(X.getSemantics()); + if (N == 0) { + return Acc; + } + assert(N >= 0 && "negative exponents not supported."); + APFloat Base = X; + int64_t RemainingExponent = N; + while (RemainingExponent > 0) { + while (RemainingExponent % 2 == 0) { + Base = Base * Base; + RemainingExponent /= 2; + } + --RemainingExponent; + Acc = Acc * Base; + } + return Acc; +} + /// Returns the negated value of the argument. inline APFloat neg(APFloat X) { X.changeSign(); diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp index f291c814886d3..a137203e8cefb 100644 --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -3793,6 +3793,71 @@ TEST(APFloatTest, abs) { EXPECT_TRUE(PSmallestNormalized.bitwiseIsEqual(abs(MSmallestNormalized))); } +TEST(APFloatTest, powi) { + + // Simple cases. + APFloat One = APFloat::getOne(APFloat::IEEEsingle(), false); + APFloat Two = APFloat(APFloat::IEEEsingle(), "2.0"); + APFloat NegTwo = APFloat(APFloat::IEEEsingle(), "-2.0"); + APFloat Four = APFloat(APFloat::IEEEsingle(), "4.0"); + APFloat Eight = APFloat(APFloat::IEEEsingle(), "8.0"); + APFloat NegEight = APFloat(APFloat::IEEEsingle(), "-8.0"); + + EXPECT_TRUE(One.bitwiseIsEqual(powi(One, 0))); + EXPECT_TRUE(One.bitwiseIsEqual(powi(One, 3))); + EXPECT_TRUE(Four.bitwiseIsEqual(powi(Two, 2))); + EXPECT_TRUE(Eight.bitwiseIsEqual(powi(Two, 3))); + + // See page 63 of IEEE 754-2019. + APFloat PosInf = APFloat::getInf(APFloat::IEEEsingle(), false); + APFloat NegInf = APFloat::getInf(APFloat::IEEEsingle(), true); + APFloat PosZero = APFloat::getZero(APFloat::IEEEsingle(), false); + APFloat NegZero = APFloat::getZero(APFloat::IEEEsingle(), true); + APFloat PosQNaN = APFloat::getNaN(APFloat::IEEEsingle(), false, 0x1337); + APFloat NegQNaN = APFloat::getNaN(APFloat::IEEEsingle(), true, 0x1337); + APInt Payload(64, 0x1337); + APFloat PosSNaN = APFloat::getSNaN(APFloat::IEEEsingle(), false, &Payload); + APFloat NegSNaN = APFloat::getSNaN(APFloat::IEEEsingle(), true, &Payload); + + EXPECT_TRUE(One.bitwiseIsEqual(powi(PosInf, 0))); + EXPECT_TRUE(NegEight.bitwiseIsEqual(powi(NegTwo, 3))); + EXPECT_TRUE(PosZero.bitwiseIsEqual(powi(PosZero, 3))); + EXPECT_TRUE(NegZero.bitwiseIsEqual(powi(NegZero, 5))); + EXPECT_TRUE(PosZero.bitwiseIsEqual(powi(NegZero, 6))); + EXPECT_TRUE(NegInf.bitwiseIsEqual(powi(NegInf, 3))); + EXPECT_TRUE(PosInf.bitwiseIsEqual(powi(NegInf, 4))); + EXPECT_TRUE(PosInf.bitwiseIsEqual(powi(PosInf, 3))); + + // Nans + EXPECT_TRUE(PosQNaN.bitwiseIsEqual(powi(PosQNaN, 1))); + EXPECT_TRUE(NegQNaN.bitwiseIsEqual(powi(NegQNaN, 1))); + // Check signaling NaN is quieted for n == 1. + EXPECT_TRUE(PosQNaN.bitwiseIsEqual(powi(PosSNaN, 1))); + EXPECT_TRUE(NegQNaN.bitwiseIsEqual(powi(NegSNaN, 1))); + + APFloat LargestDenormalF64(APFloat::IEEEdouble(), "0x1.ffffffffffffep-1023"); + APFloat NegLargestDenormalF64(APFloat::IEEEdouble(), + "-0x1.ffffffffffffep-1023"); + APFloat Smallest = APFloat::getSmallest(APFloat::IEEEsingle(), false); + APFloat NegSmallest = APFloat::getSmallest(APFloat::IEEEsingle(), true); + APFloat Largest = APFloat::getLargest(APFloat::IEEEsingle(), false); + APFloat NegLargest = APFloat::getLargest(APFloat::IEEEsingle(), true); + + EXPECT_TRUE(LargestDenormalF64.bitwiseIsEqual(powi(LargestDenormalF64, 1))); + EXPECT_TRUE( + NegLargestDenormalF64.bitwiseIsEqual(powi(NegLargestDenormalF64, 1))); + EXPECT_TRUE(Smallest.bitwiseIsEqual(powi(Smallest, 1))); + EXPECT_TRUE(NegSmallest.bitwiseIsEqual(powi(NegSmallest, 1))); + EXPECT_TRUE(Largest.bitwiseIsEqual(powi(Largest, 1))); + EXPECT_TRUE(NegLargest.bitwiseIsEqual(powi(NegLargest, 1))); + + EXPECT_TRUE(PosZero.bitwiseIsEqual(powi(Smallest, 2))); + EXPECT_TRUE(NegZero.bitwiseIsEqual(powi(NegSmallest, 3))); + EXPECT_TRUE(powi(Largest, 2).isInfinity()); + EXPECT_TRUE(powi(NegLargest, 2).isInfinity()); + EXPECT_TRUE(powi(NegLargest, 3).isNegative()); +} + TEST(APFloatTest, neg) { APFloat One = APFloat(APFloat::IEEEsingle(), "1.0"); APFloat NegOne = APFloat(APFloat::IEEEsingle(), "-1.0");