Implement IEEE-754R 2008 nextUp/nextDown functions in the guise of the function APFloat::next(bool nextDown).

rdar://13852078

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182945 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Michael Gottesman 2013-05-30 18:07:13 +00:00
parent 26266a1ece
commit 964722ca40
3 changed files with 682 additions and 25 deletions

View File

@ -81,6 +81,11 @@
although not really meaningful, and preserved in non-conversion
operations. The exponent is implicitly all 1 bits.
APFloat does not provide any exception handling beyond default exception
handling. We represent Signaling NaNs via IEEE-754R 2008 6.2.1 should clause
by encoding Signaling NaNs with the first bit of its trailing significand as
0.
TODO
====
@ -273,6 +278,8 @@ public:
opStatus mod(const APFloat &, roundingMode);
opStatus fusedMultiplyAdd(const APFloat &, const APFloat &, roundingMode);
opStatus roundToIntegral(roundingMode);
/// IEEE-754R 5.3.1: nextUp/nextDown.
opStatus next(bool nextDown);
/* Sign operations. */
void changeSign();
@ -325,6 +332,8 @@ public:
bool isPosZero() const { return isZero() && !isNegative(); }
bool isNegZero() const { return isZero() && isNegative(); }
bool isDenormal() const;
/// IEEE-754R 5.7.2: isSignaling. Returns true if this is a signaling NaN.
bool isSignaling() const;
APFloat &operator=(const APFloat &);
@ -386,6 +395,10 @@ private:
unsigned int significandLSB() const;
unsigned int significandMSB() const;
void zeroSignificand();
/// Return true if the significand excluding the integral bit is all ones.
bool isSignificandAllOnes() const;
/// Return true if the significand excluding the integral bit is all zeros.
bool isSignificandAllZeros() const;
/* Arithmetic on special values. */
opStatus addOrSubtractSpecials(const APFloat &, bool subtract);
@ -393,10 +406,26 @@ private:
opStatus multiplySpecials(const APFloat &);
opStatus modSpecials(const APFloat &);
/* Miscellany. */
/* Set to special values. */
void makeLargest(bool Neg = false);
void makeSmallest(bool Neg = false);
void makeNaN(bool SNaN = false, bool Neg = false, const APInt *fill = 0);
static APFloat makeNaN(const fltSemantics &Sem, bool SNaN, bool Negative,
const APInt *fill);
void makeNaN(bool SNaN = false, bool Neg = false, const APInt *fill = 0);
/// \name Special value queries only useful internally to APFloat
/// @{
/// Returns true if and only if the number has the smallest possible non-zero
/// magnitude in the current semantics.
bool isSmallest() const;
/// Returns true if and only if the number has the largest possible finite
/// magnitude in the current semantics.
bool isLargest() const;
/// @}
/* Miscellany. */
opStatus normalize(roundingMode, lostFraction);
opStatus addOrSubtract(const APFloat &, roundingMode, bool subtract);
cmpResult compareAbsoluteValue(const APFloat &) const;

View File

@ -684,6 +684,67 @@ APFloat::isDenormal() const {
semantics->precision - 1) == 0);
}
bool
APFloat::isSmallest() const {
// The smallest number by magnitude in our format will be the smallest
// denormal, i.e. the floating point normal with exponent being minimum
// exponent and significand bitwise equal to 1 (i.e. with MSB equal to 0).
return isNormal() && exponent == semantics->minExponent &&
significandMSB() == 0;
}
bool APFloat::isSignificandAllOnes() const {
// Test if the significand excluding the integral bit is all ones. This allows
// us to test for binade boundaries.
const integerPart *Parts = significandParts();
const unsigned PartCount = partCount();
for (unsigned i = 0; i < PartCount - 1; i++)
if (~Parts[i])
return false;
// Set the unused high bits to all ones when we compare.
const unsigned NumHighBits =
PartCount*integerPartWidth - semantics->precision + 1;
assert(NumHighBits <= integerPartWidth && "Can not have more high bits to "
"fill than integerPartWidth");
const integerPart HighBitFill =
~integerPart(0) << (integerPartWidth - NumHighBits);
if (~(Parts[PartCount - 1] | HighBitFill))
return false;
return true;
}
bool APFloat::isSignificandAllZeros() const {
// Test if the significand excluding the integral bit is all zeros. This
// allows us to test for binade boundaries.
const integerPart *Parts = significandParts();
const unsigned PartCount = partCount();
for (unsigned i = 0; i < PartCount - 1; i++)
if (Parts[i])
return false;
const unsigned NumHighBits =
PartCount*integerPartWidth - semantics->precision + 1;
assert(NumHighBits <= integerPartWidth && "Can not have more high bits to "
"clear than integerPartWidth");
const integerPart HighBitMask = ~integerPart(0) >> NumHighBits;
if (Parts[PartCount - 1] & HighBitMask)
return false;
return true;
}
bool
APFloat::isLargest() const {
// The largest number by magnitude in our format will be the floating point
// number with maximum exponent and with significand that is all ones.
return isNormal() && exponent == semantics->maxExponent
&& isSignificandAllOnes();
}
bool
APFloat::bitwiseIsEqual(const APFloat &rhs) const {
if (this == &rhs)
@ -3236,42 +3297,60 @@ APFloat::getAllOnesValue(unsigned BitWidth, bool isIEEE)
}
}
APFloat APFloat::getLargest(const fltSemantics &Sem, bool Negative) {
APFloat Val(Sem, fcNormal, Negative);
/// Make this number the largest magnitude normal number in the given
/// semantics.
void APFloat::makeLargest(bool Negative) {
// We want (in interchange format):
// sign = {Negative}
// exponent = 1..10
// significand = 1..1
category = fcNormal;
sign = Negative;
exponent = semantics->maxExponent;
Val.exponent = Sem.maxExponent; // unbiased
// Use memset to set all but the highest integerPart to all ones.
integerPart *significand = significandParts();
unsigned PartCount = partCount();
memset(significand, 0xFF, sizeof(integerPart)*(PartCount - 1));
// 1-initialize all bits....
Val.zeroSignificand();
integerPart *significand = Val.significandParts();
unsigned N = partCountForBits(Sem.precision);
for (unsigned i = 0; i != N; ++i)
significand[i] = ~((integerPart) 0);
// ...and then clear the top bits for internal consistency.
if (Sem.precision % integerPartWidth != 0)
significand[N-1] &=
(((integerPart) 1) << (Sem.precision % integerPartWidth)) - 1;
return Val;
// Set the high integerPart especially setting all unused top bits for
// internal consistency.
const unsigned NumUnusedHighBits =
PartCount*integerPartWidth - semantics->precision;
significand[PartCount - 1] = ~integerPart(0) >> NumUnusedHighBits;
}
APFloat APFloat::getSmallest(const fltSemantics &Sem, bool Negative) {
APFloat Val(Sem, fcNormal, Negative);
/// Make this number the smallest magnitude denormal number in the given
/// semantics.
void APFloat::makeSmallest(bool Negative) {
// We want (in interchange format):
// sign = {Negative}
// exponent = 0..0
// significand = 0..01
category = fcNormal;
sign = Negative;
exponent = semantics->minExponent;
APInt::tcSet(significandParts(), 1, partCount());
}
Val.exponent = Sem.minExponent; // unbiased
Val.zeroSignificand();
Val.significandParts()[0] = 1;
APFloat APFloat::getLargest(const fltSemantics &Sem, bool Negative) {
// We want (in interchange format):
// sign = {Negative}
// exponent = 1..10
// significand = 1..1
APFloat Val(Sem, uninitialized);
Val.makeLargest(Negative);
return Val;
}
APFloat APFloat::getSmallest(const fltSemantics &Sem, bool Negative) {
// We want (in interchange format):
// sign = {Negative}
// exponent = 0..0
// significand = 0..01
APFloat Val(Sem, uninitialized);
Val.makeSmallest(Negative);
return Val;
}
@ -3615,3 +3694,132 @@ bool APFloat::getExactInverse(APFloat *inv) const {
return true;
}
bool APFloat::isSignaling() const {
if (!isNaN())
return false;
// IEEE-754R 2008 6.2.1: A signaling NaN bit string should be encoded with the
// first bit of the trailing significand being 0.
return !APInt::tcExtractBit(significandParts(), semantics->precision - 2);
}
/// IEEE-754R 2008 5.3.1: nextUp/nextDown.
///
/// *NOTE* since nextDown(x) = -nextUp(-x), we only implement nextUp with
/// appropriate sign switching before/after the computation.
APFloat::opStatus APFloat::next(bool nextDown) {
// If we are performing nextDown, swap sign so we have -x.
if (nextDown)
changeSign();
// Compute nextUp(x)
opStatus result = opOK;
// Handle each float category separately.
switch (category) {
case fcInfinity:
// nextUp(+inf) = +inf
if (!isNegative())
break;
// nextUp(-inf) = -getLargest()
makeLargest(true);
break;
case fcNaN:
// IEEE-754R 2008 6.2 Par 2: nextUp(sNaN) = qNaN. Set Invalid flag.
// IEEE-754R 2008 6.2: nextUp(qNaN) = qNaN. Must be identity so we do not
// change the payload.
if (isSignaling()) {
result = opInvalidOp;
// For consistency, propogate the sign of the sNaN to the qNaN.
makeNaN(false, isNegative(), 0);
}
break;
case fcZero:
// nextUp(pm 0) = +getSmallest()
makeSmallest(false);
break;
case fcNormal:
// nextUp(-getSmallest()) = -0
if (isSmallest() && isNegative()) {
APInt::tcSet(significandParts(), 0, partCount());
category = fcZero;
exponent = 0;
break;
}
// nextUp(getLargest()) == INFINITY
if (isLargest() && !isNegative()) {
APInt::tcSet(significandParts(), 0, partCount());
category = fcInfinity;
exponent = semantics->maxExponent + 1;
break;
}
// nextUp(normal) == normal + inc.
if (isNegative()) {
// If we are negative, we need to decrement the significand.
// We only cross a binade boundary that requires adjusting the exponent
// if:
// 1. exponent != semantics->minExponent. This implies we are not in the
// smallest binade or are dealing with denormals.
// 2. Our significand excluding the integral bit is all zeros.
bool WillCrossBinadeBoundary =
exponent != semantics->minExponent && isSignificandAllZeros();
// Decrement the significand.
//
// We always do this since:
// 1. If we are dealing with a non binade decrement, by definition we
// just decrement the significand.
// 2. If we are dealing with a normal -> normal binade decrement, since
// we have an explicit integral bit the fact that all bits but the
// integral bit are zero implies that subtracting one will yield a
// significand with 0 integral bit and 1 in all other spots. Thus we
// must just adjust the exponent and set the integral bit to 1.
// 3. If we are dealing with a normal -> denormal binade decrement,
// since we set the integral bit to 0 when we represent denormals, we
// just decrement the significand.
integerPart *Parts = significandParts();
APInt::tcDecrement(Parts, partCount());
if (WillCrossBinadeBoundary) {
// Our result is a normal number. Do the following:
// 1. Set the integral bit to 1.
// 2. Decrement the exponent.
APInt::tcSetBit(Parts, semantics->precision - 1);
exponent--;
}
} else {
// If we are positive, we need to increment the significand.
// We only cross a binade boundary that requires adjusting the exponent if
// the input is not a denormal and all of said input's significand bits
// are set. If all of said conditions are true: clear the significand, set
// the integral bit to 1, and increment the exponent. If we have a
// denormal always increment since moving denormals and the numbers in the
// smallest normal binade have the same exponent in our representation.
bool WillCrossBinadeBoundary = !isDenormal() && isSignificandAllOnes();
if (WillCrossBinadeBoundary) {
integerPart *Parts = significandParts();
APInt::tcSet(Parts, 0, partCount());
APInt::tcSetBit(Parts, semantics->precision - 1);
assert(exponent != semantics->maxExponent &&
"We can not increment an exponent beyond the maxExponent allowed"
" by the given floating point semantics.");
exponent++;
} else {
incrementSignificand();
}
}
break;
}
// If we are performing nextDown, swap sign so we have -nextUp(-x)
if (nextDown)
changeSign();
return result;
}

View File

@ -33,6 +33,426 @@ static std::string convertToString(double d, unsigned Prec, unsigned Pad) {
namespace {
TEST(APFloatTest, isSignaling) {
// We test qNaN, -qNaN, +sNaN, -sNaN with and without payloads. *NOTE* The
// positive/negative distinction is included only since the getQNaN/getSNaN
// API provides the option.
APInt payload = APInt::getOneBitSet(4, 2);
EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, false).isSignaling());
EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, true).isSignaling());
EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, false, &payload).isSignaling());
EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, true, &payload).isSignaling());
EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, false).isSignaling());
EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, true).isSignaling());
EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, false, &payload).isSignaling());
EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, true, &payload).isSignaling());
}
TEST(APFloatTest, next) {
APFloat test(APFloat::IEEEquad, APFloat::uninitialized);
APFloat expected(APFloat::IEEEquad, APFloat::uninitialized);
// 1. Test Special Cases Values.
//
// Test all special values for nextUp and nextDown perscribed by IEEE-754R
// 2008. These are:
// 1. +inf
// 2. -inf
// 3. getLargest()
// 4. -getLargest()
// 5. getSmallest()
// 6. -getSmallest()
// 7. qNaN
// 8. sNaN
// 9. +0
// 10. -0
// nextUp(+inf) = +inf.
test = APFloat::getInf(APFloat::IEEEquad, false);
expected = APFloat::getInf(APFloat::IEEEquad, false);
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isInfinity());
EXPECT_TRUE(!test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(+inf) = -nextUp(-inf) = -(-getLargest()) = getLargest()
test = APFloat::getInf(APFloat::IEEEquad, false);
expected = APFloat::getLargest(APFloat::IEEEquad, false);
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(!test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(-inf) = -getLargest()
test = APFloat::getInf(APFloat::IEEEquad, true);
expected = APFloat::getLargest(APFloat::IEEEquad, true);
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-inf) = -nextUp(+inf) = -(+inf) = -inf.
test = APFloat::getInf(APFloat::IEEEquad, true);
expected = APFloat::getInf(APFloat::IEEEquad, true);
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.isInfinity() && test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(getLargest()) = +inf
test = APFloat::getLargest(APFloat::IEEEquad, false);
expected = APFloat::getInf(APFloat::IEEEquad, false);
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isInfinity() && !test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(getLargest()) = -nextUp(-getLargest())
// = -(-getLargest() + inc)
// = getLargest() - inc.
test = APFloat::getLargest(APFloat::IEEEquad, false);
expected = APFloat(APFloat::IEEEquad,
"0x1.fffffffffffffffffffffffffffep+16383");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(!test.isInfinity() && !test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(-getLargest()) = -getLargest() + inc.
test = APFloat::getLargest(APFloat::IEEEquad, true);
expected = APFloat(APFloat::IEEEquad,
"-0x1.fffffffffffffffffffffffffffep+16383");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-getLargest()) = -nextUp(getLargest()) = -(inf) = -inf.
test = APFloat::getLargest(APFloat::IEEEquad, true);
expected = APFloat::getInf(APFloat::IEEEquad, true);
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.isInfinity() && test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(getSmallest()) = getSmallest() + inc.
test = APFloat(APFloat::IEEEquad, "0x0.0000000000000000000000000001p-16382");
expected = APFloat(APFloat::IEEEquad,
"0x0.0000000000000000000000000002p-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(getSmallest()) = -nextUp(-getSmallest()) = -(-0) = +0.
test = APFloat(APFloat::IEEEquad, "0x0.0000000000000000000000000001p-16382");
expected = APFloat::getZero(APFloat::IEEEquad, false);
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.isZero() && !test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(-getSmallest()) = -0.
test = APFloat(APFloat::IEEEquad, "-0x0.0000000000000000000000000001p-16382");
expected = APFloat::getZero(APFloat::IEEEquad, true);
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isZero() && test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-getSmallest()) = -nextUp(getSmallest()) = -getSmallest() - inc.
test = APFloat(APFloat::IEEEquad, "-0x0.0000000000000000000000000001p-16382");
expected = APFloat(APFloat::IEEEquad,
"-0x0.0000000000000000000000000002p-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(qNaN) = qNaN
test = APFloat::getQNaN(APFloat::IEEEquad, false);
expected = APFloat::getQNaN(APFloat::IEEEquad, false);
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(qNaN) = qNaN
test = APFloat::getQNaN(APFloat::IEEEquad, false);
expected = APFloat::getQNaN(APFloat::IEEEquad, false);
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(sNaN) = qNaN
test = APFloat::getSNaN(APFloat::IEEEquad, false);
expected = APFloat::getQNaN(APFloat::IEEEquad, false);
EXPECT_EQ(test.next(false), APFloat::opInvalidOp);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(sNaN) = qNaN
test = APFloat::getSNaN(APFloat::IEEEquad, false);
expected = APFloat::getQNaN(APFloat::IEEEquad, false);
EXPECT_EQ(test.next(true), APFloat::opInvalidOp);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(+0) = +getSmallest()
test = APFloat::getZero(APFloat::IEEEquad, false);
expected = APFloat::getSmallest(APFloat::IEEEquad, false);
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(+0) = -nextUp(-0) = -getSmallest()
test = APFloat::getZero(APFloat::IEEEquad, false);
expected = APFloat::getSmallest(APFloat::IEEEquad, true);
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(-0) = +getSmallest()
test = APFloat::getZero(APFloat::IEEEquad, true);
expected = APFloat::getSmallest(APFloat::IEEEquad, false);
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-0) = -nextUp(0) = -getSmallest()
test = APFloat::getZero(APFloat::IEEEquad, true);
expected = APFloat::getSmallest(APFloat::IEEEquad, true);
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// 2. Binade Boundary Tests.
// 2a. Test denormal <-> normal binade boundaries.
// * nextUp(+Largest Denormal) -> +Smallest Normal.
// * nextDown(-Largest Denormal) -> -Smallest Normal.
// * nextUp(-Smallest Normal) -> -Largest Denormal.
// * nextDown(+Smallest Normal) -> +Largest Denormal.
// nextUp(+Largest Denormal) -> +Smallest Normal.
test = APFloat(APFloat::IEEEquad, "0x0.ffffffffffffffffffffffffffffp-16382");
expected = APFloat(APFloat::IEEEquad,
"0x1.0000000000000000000000000000p-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_FALSE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-Largest Denormal) -> -Smallest Normal.
test = APFloat(APFloat::IEEEquad,
"-0x0.ffffffffffffffffffffffffffffp-16382");
expected = APFloat(APFloat::IEEEquad,
"-0x1.0000000000000000000000000000p-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_FALSE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(-Smallest Normal) -> -LargestDenormal.
test = APFloat(APFloat::IEEEquad,
"-0x1.0000000000000000000000000000p-16382");
expected = APFloat(APFloat::IEEEquad,
"-0x0.ffffffffffffffffffffffffffffp-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(+Smallest Normal) -> +Largest Denormal.
test = APFloat(APFloat::IEEEquad,
"+0x1.0000000000000000000000000000p-16382");
expected = APFloat(APFloat::IEEEquad,
"+0x0.ffffffffffffffffffffffffffffp-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// 2b. Test normal <-> normal binade boundaries.
// * nextUp(-Normal Binade Boundary) -> -Normal Binade Boundary + 1.
// * nextDown(+Normal Binade Boundary) -> +Normal Binade Boundary - 1.
// * nextUp(+Normal Binade Boundary - 1) -> +Normal Binade Boundary.
// * nextDown(-Normal Binade Boundary + 1) -> -Normal Binade Boundary.
// nextUp(-Normal Binade Boundary) -> -Normal Binade Boundary + 1.
test = APFloat(APFloat::IEEEquad, "-0x1p+1");
expected = APFloat(APFloat::IEEEquad,
"-0x1.ffffffffffffffffffffffffffffp+0");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(+Normal Binade Boundary) -> +Normal Binade Boundary - 1.
test = APFloat(APFloat::IEEEquad, "0x1p+1");
expected = APFloat(APFloat::IEEEquad, "0x1.ffffffffffffffffffffffffffffp+0");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(+Normal Binade Boundary - 1) -> +Normal Binade Boundary.
test = APFloat(APFloat::IEEEquad, "0x1.ffffffffffffffffffffffffffffp+0");
expected = APFloat(APFloat::IEEEquad, "0x1p+1");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-Normal Binade Boundary + 1) -> -Normal Binade Boundary.
test = APFloat(APFloat::IEEEquad, "-0x1.ffffffffffffffffffffffffffffp+0");
expected = APFloat(APFloat::IEEEquad, "-0x1p+1");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// 2c. Test using next at binade boundaries with a direction away from the
// binade boundary. Away from denormal <-> normal boundaries.
//
// This is to make sure that even though we are at a binade boundary, since
// we are rounding away, we do not trigger the binade boundary code. Thus we
// test:
// * nextUp(-Largest Denormal) -> -Largest Denormal + inc.
// * nextDown(+Largest Denormal) -> +Largest Denormal - inc.
// * nextUp(+Smallest Normal) -> +Smallest Normal + inc.
// * nextDown(-Smallest Normal) -> -Smallest Normal - inc.
// nextUp(-Largest Denormal) -> -Largest Denormal + inc.
test = APFloat(APFloat::IEEEquad, "-0x0.ffffffffffffffffffffffffffffp-16382");
expected = APFloat(APFloat::IEEEquad,
"-0x0.fffffffffffffffffffffffffffep-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
EXPECT_TRUE(test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(+Largest Denormal) -> +Largest Denormal - inc.
test = APFloat(APFloat::IEEEquad, "0x0.ffffffffffffffffffffffffffffp-16382");
expected = APFloat(APFloat::IEEEquad,
"0x0.fffffffffffffffffffffffffffep-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
EXPECT_TRUE(!test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(+Smallest Normal) -> +Smallest Normal + inc.
test = APFloat(APFloat::IEEEquad, "0x1.0000000000000000000000000000p-16382");
expected = APFloat(APFloat::IEEEquad,
"0x1.0000000000000000000000000001p-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(!test.isDenormal());
EXPECT_TRUE(!test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-Smallest Normal) -> -Smallest Normal - inc.
test = APFloat(APFloat::IEEEquad, "-0x1.0000000000000000000000000000p-16382");
expected = APFloat(APFloat::IEEEquad,
"-0x1.0000000000000000000000000001p-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(!test.isDenormal());
EXPECT_TRUE(test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// 2d. Test values which cause our exponent to go to min exponent. This
// is to ensure that guards in the code to check for min exponent
// trigger properly.
// * nextUp(-0x1p-16381) -> -0x1.ffffffffffffffffffffffffffffp-16382
// * nextDown(-0x1.ffffffffffffffffffffffffffffp-16382) ->
// -0x1p-16381
// * nextUp(0x1.ffffffffffffffffffffffffffffp-16382) -> 0x1p-16382
// * nextDown(0x1p-16382) -> 0x1.ffffffffffffffffffffffffffffp-16382
// nextUp(-0x1p-16381) -> -0x1.ffffffffffffffffffffffffffffp-16382
test = APFloat(APFloat::IEEEquad, "-0x1p-16381");
expected = APFloat(APFloat::IEEEquad,
"-0x1.ffffffffffffffffffffffffffffp-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-0x1.ffffffffffffffffffffffffffffp-16382) ->
// -0x1p-16381
test = APFloat(APFloat::IEEEquad, "-0x1.ffffffffffffffffffffffffffffp-16382");
expected = APFloat(APFloat::IEEEquad, "-0x1p-16381");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(0x1.ffffffffffffffffffffffffffffp-16382) -> 0x1p-16381
test = APFloat(APFloat::IEEEquad, "0x1.ffffffffffffffffffffffffffffp-16382");
expected = APFloat(APFloat::IEEEquad, "0x1p-16381");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(0x1p-16381) -> 0x1.ffffffffffffffffffffffffffffp-16382
test = APFloat(APFloat::IEEEquad, "0x1p-16381");
expected = APFloat(APFloat::IEEEquad,
"0x1.ffffffffffffffffffffffffffffp-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// 3. Now we test both denormal/normal computation which will not cause us
// to go across binade boundaries. Specifically we test:
// * nextUp(+Denormal) -> +Denormal.
// * nextDown(+Denormal) -> +Denormal.
// * nextUp(-Denormal) -> -Denormal.
// * nextDown(-Denormal) -> -Denormal.
// * nextUp(+Normal) -> +Normal.
// * nextDown(+Normal) -> +Normal.
// * nextUp(-Normal) -> -Normal.
// * nextDown(-Normal) -> -Normal.
// nextUp(+Denormal) -> +Denormal.
test = APFloat(APFloat::IEEEquad,
"0x0.ffffffffffffffffffffffff000cp-16382");
expected = APFloat(APFloat::IEEEquad,
"0x0.ffffffffffffffffffffffff000dp-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
EXPECT_TRUE(!test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(+Denormal) -> +Denormal.
test = APFloat(APFloat::IEEEquad,
"0x0.ffffffffffffffffffffffff000cp-16382");
expected = APFloat(APFloat::IEEEquad,
"0x0.ffffffffffffffffffffffff000bp-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
EXPECT_TRUE(!test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(-Denormal) -> -Denormal.
test = APFloat(APFloat::IEEEquad,
"-0x0.ffffffffffffffffffffffff000cp-16382");
expected = APFloat(APFloat::IEEEquad,
"-0x0.ffffffffffffffffffffffff000bp-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
EXPECT_TRUE(test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-Denormal) -> -Denormal
test = APFloat(APFloat::IEEEquad,
"-0x0.ffffffffffffffffffffffff000cp-16382");
expected = APFloat(APFloat::IEEEquad,
"-0x0.ffffffffffffffffffffffff000dp-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
EXPECT_TRUE(test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(+Normal) -> +Normal.
test = APFloat(APFloat::IEEEquad,
"0x1.ffffffffffffffffffffffff000cp-16000");
expected = APFloat(APFloat::IEEEquad,
"0x1.ffffffffffffffffffffffff000dp-16000");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(!test.isDenormal());
EXPECT_TRUE(!test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(+Normal) -> +Normal.
test = APFloat(APFloat::IEEEquad,
"0x1.ffffffffffffffffffffffff000cp-16000");
expected = APFloat(APFloat::IEEEquad,
"0x1.ffffffffffffffffffffffff000bp-16000");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(!test.isDenormal());
EXPECT_TRUE(!test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(-Normal) -> -Normal.
test = APFloat(APFloat::IEEEquad,
"-0x1.ffffffffffffffffffffffff000cp-16000");
expected = APFloat(APFloat::IEEEquad,
"-0x1.ffffffffffffffffffffffff000bp-16000");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(!test.isDenormal());
EXPECT_TRUE(test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-Normal) -> -Normal.
test = APFloat(APFloat::IEEEquad,
"-0x1.ffffffffffffffffffffffff000cp-16000");
expected = APFloat(APFloat::IEEEquad,
"-0x1.ffffffffffffffffffffffff000dp-16000");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(!test.isDenormal());
EXPECT_TRUE(test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
}
TEST(APFloatTest, FMA) {
APFloat::roundingMode rdmd = APFloat::rmNearestTiesToEven;