mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-02 07:11:49 +00:00
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:
parent
26266a1ece
commit
964722ca40
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user