diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h index ca4138b825a..21b8c86d1d5 100644 --- a/include/llvm/ADT/APFloat.h +++ b/include/llvm/ADT/APFloat.h @@ -353,6 +353,10 @@ namespace llvm { unsigned FormatPrecision = 0, unsigned FormatMaxPadding = 3) const; + /// getExactInverse - If this value has an exact multiplicative inverse, + /// store it in inv and return true. + bool getExactInverse(APFloat *inv) const; + private: /* Trivial queries. */ diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index 93806facff0..abe55753181 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -3562,3 +3562,29 @@ void APFloat::toString(SmallVectorImpl &Str, for (; I != NDigits; ++I) Str.push_back(buffer[NDigits-I-1]); } + +bool APFloat::getExactInverse(APFloat *inv) const { + // We can only guarantee the existance of an exact inverse for IEEE floats. + if (semantics != &IEEEhalf && semantics != &IEEEsingle && + semantics != &IEEEdouble && semantics != &IEEEquad) + return false; + + // Special floats and denormals have no exact inverse. + if (category != fcNormal) + return false; + + // Check that the number is a power of two by making sure that only the + // integer bit is set in the significand. + if (significandLSB() != semantics->precision - 1) + return false; + + // Get the inverse. + APFloat reciprocal(*semantics, 1ULL); + if (reciprocal.divide(*this, rmNearestTiesToEven) != opOK) + return false; + + if (inv) + *inv = reciprocal; + + return true; +} diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp index 964b04da473..dea4a65b88a 100644 --- a/unittests/ADT/APFloatTest.cpp +++ b/unittests/ADT/APFloatTest.cpp @@ -576,4 +576,27 @@ TEST(APFloatTest, StringHexadecimalExponentDeath) { #endif #endif +TEST(APFloatTest, exactInverse) { + APFloat inv(0.0f); + + // Trivial operation. + EXPECT_TRUE(APFloat(2.0).getExactInverse(&inv)); + EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(0.5))); + EXPECT_TRUE(APFloat(2.0f).getExactInverse(&inv)); + EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(0.5f))); + + // FLT_MIN + EXPECT_TRUE(APFloat(1.17549435e-38f).getExactInverse(&inv)); + EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(8.5070592e+37f))); + + // Large float + EXPECT_TRUE(APFloat(1.7014118e38f).getExactInverse(&inv)); + EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(5.8774718e-39f))); + + // Zero + EXPECT_FALSE(APFloat(0.0).getExactInverse(0)); + // Denormalized float + EXPECT_FALSE(APFloat(1.40129846e-45f).getExactInverse(0)); +} + }