Skip to content

Commit

Permalink
APFloat: Add frexp
Browse files Browse the repository at this point in the history
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@263950 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
arsenm committed Mar 21, 2016
1 parent c8d042b commit 7c9226f
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 2 deletions.
9 changes: 9 additions & 0 deletions include/llvm/ADT/APFloat.h
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,8 @@ class APFloat {
/// \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
Expand Down Expand Up @@ -570,6 +572,7 @@ class APFloat {
const APInt *fill);
void makeInf(bool Neg = false);
void makeZero(bool Neg = false);
void makeQuiet();

/// @}

Expand Down Expand Up @@ -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();
Expand Down
26 changes: 25 additions & 1 deletion lib/Support/APFloat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -3981,3 +3986,22 @@ APFloat llvm::scalbn(APFloat X, int Exp, APFloat::roundingMode RoundingMode) {
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);
}
128 changes: 127 additions & 1 deletion unittests/ADT/APFloatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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));
}
}

0 comments on commit 7c9226f

Please sign in to comment.