[llvm] r263950 - APFloat: Add frexp

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 21 09:49:17 PDT 2016


Author: arsenm
Date: Mon Mar 21 11:49:16 2016
New Revision: 263950

URL: http://llvm.org/viewvc/llvm-project?rev=263950&view=rev
Log:
APFloat: Add frexp

Modified:
    llvm/trunk/include/llvm/ADT/APFloat.h
    llvm/trunk/lib/Support/APFloat.cpp
    llvm/trunk/unittests/ADT/APFloatTest.cpp

Modified: llvm/trunk/include/llvm/ADT/APFloat.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/APFloat.h?rev=263950&r1=263949&r2=263950&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/APFloat.h (original)
+++ llvm/trunk/include/llvm/ADT/APFloat.h Mon Mar 21 11:49:16 2016
@@ -516,6 +516,8 @@ public:
   /// \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 @@ private:
                          const APInt *fill);
   void makeInf(bool Neg = false);
   void makeZero(bool Neg = false);
+  void makeQuiet();
 
   /// @}
 
@@ -645,6 +648,12 @@ hash_code hash_value(const APFloat &Arg)
 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();

Modified: llvm/trunk/lib/Support/APFloat.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/APFloat.cpp?rev=263950&r1=263949&r2=263950&view=diff
==============================================================================
--- llvm/trunk/lib/Support/APFloat.cpp (original)
+++ llvm/trunk/lib/Support/APFloat.cpp Mon Mar 21 11:49:16 2016
@@ -3942,7 +3942,12 @@ APFloat::makeZero(bool Negative) {
   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 @@ APFloat llvm::scalbn(APFloat X, int Exp,
   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);
+}

Modified: llvm/trunk/unittests/ADT/APFloatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/APFloatTest.cpp?rev=263950&r1=263949&r2=263950&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/APFloatTest.cpp (original)
+++ llvm/trunk/unittests/ADT/APFloatTest.cpp Mon Mar 21 11:49:16 2016
@@ -1314,7 +1314,7 @@ TEST(APFloatTest, roundToIntegral) {
   P.roundToIntegral(APFloat::rmTowardZero);
   EXPECT_TRUE(std::isinf(P.convertToDouble()) && P.convertToDouble() < 0.0);
 }
-  
+
 TEST(APFloatTest, isInteger) {
   APFloat T(-0.0);
   EXPECT_TRUE(T.isInteger());
@@ -3018,4 +3018,130 @@ TEST(APFloatTest, scalbn) {
     APFloat(APFloat::IEEEdouble, "0x1p-103")
     .bitwiseIsEqual(scalbn(APFloat(APFloat::IEEEdouble, "0x1p-51"), -52, RM)));
 }
+
+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));
+}
 }




More information about the llvm-commits mailing list