[APFloat] Properly implement DoubleAPFloat::roundToIntegral
The previous implementation did not correctly handle double-doubles like 0x1p100 + 0x1p1 as the low order component would need more than a 106-bit significand to represent.
This commit is contained in:
parent
51e825dbfb
commit
0a23b22d1d
@ -4949,6 +4949,21 @@ DoubleAPFloat &DoubleAPFloat::operator=(const DoubleAPFloat &RHS) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Returns a result such that:
|
||||
// 1. abs(Lo) <= ulp(Hi)/2
|
||||
// 2. Hi == RTNE(Hi + Lo)
|
||||
// 3. Hi + Lo == X + Y
|
||||
//
|
||||
// Requires that log2(X) >= log2(Y).
|
||||
static std::pair<APFloat, APFloat> fastTwoSum(APFloat X, APFloat Y) {
|
||||
if (!X.isFinite())
|
||||
return {X, APFloat::getZero(X.getSemantics(), /*Negative=*/false)};
|
||||
APFloat Hi = X + Y;
|
||||
APFloat Delta = Hi - X;
|
||||
APFloat Lo = Y - Delta;
|
||||
return {Hi, Lo};
|
||||
}
|
||||
|
||||
// Implement addition, subtraction, multiplication and division based on:
|
||||
// "Software for Doubled-Precision Floating-Point Computations",
|
||||
// by Seppo Linnainmaa, ACM TOMS vol 7 no 3, September 1981, pages 272-283.
|
||||
@ -5218,10 +5233,78 @@ DoubleAPFloat::fusedMultiplyAdd(const DoubleAPFloat &Multiplicand,
|
||||
|
||||
APFloat::opStatus DoubleAPFloat::roundToIntegral(APFloat::roundingMode RM) {
|
||||
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
|
||||
APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
|
||||
auto Ret = Tmp.roundToIntegral(RM);
|
||||
*this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
|
||||
return Ret;
|
||||
const APFloat &Hi = getFirst();
|
||||
const APFloat &Lo = getSecond();
|
||||
|
||||
APFloat RoundedHi = Hi;
|
||||
const opStatus HiStatus = RoundedHi.roundToIntegral(RM);
|
||||
|
||||
// We can reduce the problem to just the high part if the input:
|
||||
// 1. Represents a non-finite value.
|
||||
// 2. Has a component which is zero.
|
||||
if (!Hi.isFiniteNonZero() || Lo.isZero()) {
|
||||
Floats[0] = std::move(RoundedHi);
|
||||
Floats[1].makeZero(/*Neg=*/false);
|
||||
return HiStatus;
|
||||
}
|
||||
|
||||
// Adjust `Rounded` in the direction of `TieBreaker` if `ToRound` was at a
|
||||
// halfway point.
|
||||
auto RoundToNearestHelper = [](APFloat ToRound, APFloat Rounded,
|
||||
APFloat TieBreaker) {
|
||||
// RoundingError tells us which direction we rounded:
|
||||
// - RoundingError > 0: we rounded up.
|
||||
// - RoundingError < 0: we rounded down.
|
||||
// Sterbenz' lemma ensures that RoundingError is exact.
|
||||
const APFloat RoundingError = Rounded - ToRound;
|
||||
if (TieBreaker.isNonZero() &&
|
||||
TieBreaker.isNegative() != RoundingError.isNegative() &&
|
||||
abs(RoundingError).isExactlyValue(0.5))
|
||||
Rounded.add(
|
||||
APFloat::getOne(Rounded.getSemantics(), TieBreaker.isNegative()),
|
||||
rmNearestTiesToEven);
|
||||
return Rounded;
|
||||
};
|
||||
|
||||
// Case 1: Hi is not an integer.
|
||||
// Special cases are for rounding modes that are sensitive to ties.
|
||||
if (RoundedHi != Hi) {
|
||||
// We need to consider the case where Hi was between two integers and the
|
||||
// rounding mode broke the tie when, in fact, Lo may have had a different
|
||||
// sign than Hi.
|
||||
if (RM == rmNearestTiesToAway || RM == rmNearestTiesToEven)
|
||||
RoundedHi = RoundToNearestHelper(Hi, RoundedHi, Lo);
|
||||
|
||||
Floats[0] = std::move(RoundedHi);
|
||||
Floats[1].makeZero(/*Neg=*/false);
|
||||
return HiStatus;
|
||||
}
|
||||
|
||||
// Case 2: Hi is an integer.
|
||||
// Special cases are for rounding modes which are rounding towards or away from zero.
|
||||
RoundingMode LoRoundingMode;
|
||||
if (RM == rmTowardZero)
|
||||
// When our input is positive, we want the Lo component rounded toward
|
||||
// negative infinity to get the smallest result magnitude. Likewise,
|
||||
// negative inputs want the Lo component rounded toward positive infinity.
|
||||
LoRoundingMode = isNegative() ? rmTowardPositive : rmTowardNegative;
|
||||
else
|
||||
LoRoundingMode = RM;
|
||||
|
||||
APFloat RoundedLo = Lo;
|
||||
const opStatus LoStatus = RoundedLo.roundToIntegral(LoRoundingMode);
|
||||
if (LoRoundingMode == rmNearestTiesToAway)
|
||||
// We need to consider the case where Lo was between two integers and the
|
||||
// rounding mode broke the tie when, in fact, Hi may have had a different
|
||||
// sign than Lo.
|
||||
RoundedLo = RoundToNearestHelper(Lo, RoundedLo, Hi);
|
||||
|
||||
// We must ensure that the final result has no overlap between the two APFloat values.
|
||||
std::tie(RoundedHi, RoundedLo) = fastTwoSum(RoundedHi, RoundedLo);
|
||||
|
||||
Floats[0] = std::move(RoundedHi);
|
||||
Floats[1] = std::move(RoundedLo);
|
||||
return LoStatus;
|
||||
}
|
||||
|
||||
void DoubleAPFloat::changeSign() {
|
||||
|
@ -16,9 +16,11 @@
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@ -2661,6 +2663,39 @@ TEST(APFloatTest, Float8UZConvert) {
|
||||
}
|
||||
}
|
||||
|
||||
struct DD {
|
||||
double Hi;
|
||||
double Lo;
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
static APFloat makeDoubleAPFloat(T Hi, U Lo) {
|
||||
APFloat HiFloat{APFloat::IEEEdouble(), APFloat::uninitialized};
|
||||
if constexpr (std::is_same_v<decltype(Hi), APFloat>) {
|
||||
HiFloat = Hi;
|
||||
} else if constexpr (std::is_same_v<decltype(Hi), double>) {
|
||||
HiFloat = APFloat{Hi};
|
||||
} else {
|
||||
HiFloat = {APFloat::IEEEdouble(), Hi};
|
||||
}
|
||||
|
||||
APFloat LoFloat{APFloat::IEEEdouble(), APFloat::uninitialized};
|
||||
if constexpr (std::is_same_v<decltype(Lo), APFloat>) {
|
||||
LoFloat = Lo;
|
||||
} else if constexpr (std::is_same_v<decltype(Lo), double>) {
|
||||
LoFloat = APFloat{Lo};
|
||||
} else {
|
||||
LoFloat = {APFloat::IEEEdouble(), Lo};
|
||||
}
|
||||
|
||||
APInt Bits = LoFloat.bitcastToAPInt().concat(HiFloat.bitcastToAPInt());
|
||||
return APFloat(APFloat::PPCDoubleDouble(), Bits);
|
||||
}
|
||||
|
||||
static APFloat makeDoubleAPFloat(DD X) {
|
||||
return makeDoubleAPFloat(X.Hi, X.Lo);
|
||||
}
|
||||
|
||||
TEST(APFloatTest, PPCDoubleDouble) {
|
||||
APFloat test(APFloat::PPCDoubleDouble(), "1.0");
|
||||
EXPECT_EQ(0x3ff0000000000000ull, test.bitcastToAPInt().getRawData()[0]);
|
||||
@ -5315,18 +5350,452 @@ TEST(APFloatTest, PPCDoubleDoubleFMA) {
|
||||
APFloat(APFloat::PPCDoubleDouble(), "10").compare(A));
|
||||
}
|
||||
|
||||
TEST(APFloatTest, PPCDoubleDoubleRoundToIntegral) {
|
||||
{
|
||||
APFloat A(APFloat::PPCDoubleDouble(), "1.5");
|
||||
A.roundToIntegral(APFloat::rmNearestTiesToEven);
|
||||
EXPECT_EQ(APFloat::cmpEqual,
|
||||
APFloat(APFloat::PPCDoubleDouble(), "2").compare(A));
|
||||
struct PPCDoubleDoubleRoundToIntegralTestCase {
|
||||
DD Input;
|
||||
DD Rounded[5] = {};
|
||||
constexpr PPCDoubleDoubleRoundToIntegralTestCase &
|
||||
withRounded(DD R, APFloat::roundingMode RM) {
|
||||
Rounded[static_cast<std::underlying_type_t<APFloat::roundingMode>>(RM)] = R;
|
||||
return *this;
|
||||
}
|
||||
{
|
||||
APFloat A(APFloat::PPCDoubleDouble(), "2.5");
|
||||
A.roundToIntegral(APFloat::rmNearestTiesToEven);
|
||||
EXPECT_EQ(APFloat::cmpEqual,
|
||||
APFloat(APFloat::PPCDoubleDouble(), "2").compare(A));
|
||||
};
|
||||
|
||||
auto ppcDoubleDoubleRoundToIntegralTests() {
|
||||
constexpr double Eps = std::numeric_limits<double>::epsilon();
|
||||
constexpr double HalfEps = Eps / 2.0;
|
||||
constexpr double QuarterEps = Eps / 4.0;
|
||||
constexpr double SmallestNormal = std::numeric_limits<double>::min();
|
||||
constexpr double EvenIntegerThreshold{uint64_t{1}
|
||||
<< std::numeric_limits<double>::digits};
|
||||
constexpr double Inf = std::numeric_limits<double>::infinity();
|
||||
constexpr double QNaN = std::numeric_limits<double>::quiet_NaN();
|
||||
using TestCase = PPCDoubleDoubleRoundToIntegralTestCase;
|
||||
static constexpr auto TestCases = std::array{
|
||||
// 1. Zeros and Basic Integers
|
||||
// Input: Positive Zero (0.0, 0.0)
|
||||
TestCase({{0.0, 0.0}})
|
||||
.withRounded({0.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({0.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({0.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({0.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({0.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: Negative Zero (-0.0, 0.0)
|
||||
TestCase({{-0.0, 0.0}})
|
||||
.withRounded({-0.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({-0.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({-0.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({-0.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({-0.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: Positive Even (2.0, 0.0)
|
||||
TestCase({{2.0, 0.0}})
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: Positive Odd (3.0, 0.0)
|
||||
TestCase({{3.0, 0.0}})
|
||||
.withRounded({3.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: Negative Even (-2.0, 0.0)
|
||||
TestCase({{-2.0, 0.0}})
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// 2. General Fractions (Non-Ties)
|
||||
// Input: 2.3
|
||||
TestCase({{2.3, 0.0}})
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: 2.7
|
||||
TestCase({{2.7, 0.0}})
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: -2.3
|
||||
TestCase({{-2.3, 0.0}})
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({-3.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: -2.7
|
||||
TestCase({{-2.7, 0.0}})
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({-3.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({-3.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({-3.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: 2.3 + Tiny
|
||||
TestCase({{2.3, SmallestNormal}})
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// 3. Exact Midpoints (Ties at N.5)
|
||||
// Input: 0.5
|
||||
TestCase({{0.5, 0.0}})
|
||||
.withRounded({0.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({0.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({0.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: 1.5 (Odd base)
|
||||
TestCase({{1.5, 0.0}})
|
||||
.withRounded({1.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: 2.5 (Even base)
|
||||
TestCase({{2.5, 0.0}})
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: -0.5
|
||||
TestCase({{-0.5, 0.0}})
|
||||
.withRounded({-0.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({-1.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({-0.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({-1.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({-0.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: -1.5 (Odd base)
|
||||
TestCase({{-1.5, 0.0}})
|
||||
.withRounded({-1.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({-1.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: -2.5 (Even base)
|
||||
TestCase({{-2.5, 0.0}})
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({-3.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({-3.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// 4. Near Midpoints (lo breaks the tie)
|
||||
// Input: Slightly > 2.5
|
||||
TestCase({{2.5, SmallestNormal}})
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: Slightly < 2.5
|
||||
TestCase({{2.5, -SmallestNormal}})
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: Slightly > 1.5
|
||||
TestCase({{1.5, SmallestNormal}})
|
||||
.withRounded({1.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: Slightly < 1.5
|
||||
TestCase({{1.5, -SmallestNormal}})
|
||||
.withRounded({1.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: Slightly > -2.5 (closer to 0)
|
||||
TestCase({{-2.5, SmallestNormal}})
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({-3.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: Slightly < -2.5 (further from 0)
|
||||
TestCase({{-2.5, -SmallestNormal}})
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({-3.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({-3.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({-3.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// 5. Near Integers (lo crosses the integer boundary)
|
||||
// Input: Slightly > 2.0
|
||||
TestCase({{2.0, SmallestNormal}})
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({3.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: Slightly < 2.0 (1.99...)
|
||||
TestCase({{2.0, -SmallestNormal}})
|
||||
.withRounded({1.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: Slightly > -2.0 (-1.99...)
|
||||
TestCase({{-2.0, SmallestNormal}})
|
||||
.withRounded({-1.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({-1.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: Slightly < -2.0
|
||||
TestCase({{-2.0, -SmallestNormal}})
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({-3.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({-2.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: Slightly > 0.0
|
||||
TestCase({{SmallestNormal, 0.0}})
|
||||
.withRounded({0.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({0.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({0.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({0.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: Slightly < 0.0
|
||||
TestCase({{-SmallestNormal, 0.0}})
|
||||
.withRounded({-0.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({-1.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({-0.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({-0.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({-0.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// 6. Boundary of Canonicalization (Maximum lo)
|
||||
// Input: 1.0 + Max lo (1 + 2^-53)
|
||||
TestCase({{1.0, HalfEps}})
|
||||
.withRounded({1.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({2.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: 1.0 - Max lo (1 - 2^-54)
|
||||
TestCase({{1.0, -QuarterEps}})
|
||||
.withRounded({0.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({0.0, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({1.0, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// 7. Large Magnitudes (Beyond 2^53). N = EvenIntegerThreshold (Even)
|
||||
// Input: EvenIntegerThreshold (Exact)
|
||||
TestCase({{EvenIntegerThreshold, 0.0}})
|
||||
.withRounded({EvenIntegerThreshold, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({EvenIntegerThreshold, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({EvenIntegerThreshold, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({EvenIntegerThreshold, 0.0},
|
||||
APFloat::rmNearestTiesToAway)
|
||||
.withRounded({EvenIntegerThreshold, 0.0},
|
||||
APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: EvenIntegerThreshold+1 (Exact)
|
||||
TestCase({{EvenIntegerThreshold, 1.0}})
|
||||
.withRounded({EvenIntegerThreshold, 1.0}, APFloat::rmTowardZero)
|
||||
.withRounded({EvenIntegerThreshold, 1.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({EvenIntegerThreshold, 1.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({EvenIntegerThreshold, 1.0},
|
||||
APFloat::rmNearestTiesToAway)
|
||||
.withRounded({EvenIntegerThreshold, 1.0},
|
||||
APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Fractions
|
||||
// Input: EvenIntegerThreshold+0.25
|
||||
TestCase({{EvenIntegerThreshold, 0.25}})
|
||||
.withRounded({EvenIntegerThreshold, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({EvenIntegerThreshold, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({EvenIntegerThreshold, 1.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({EvenIntegerThreshold, 0.0},
|
||||
APFloat::rmNearestTiesToAway)
|
||||
.withRounded({EvenIntegerThreshold, 0.0},
|
||||
APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: EvenIntegerThreshold+0.75
|
||||
TestCase({{EvenIntegerThreshold, 0.75}})
|
||||
.withRounded({EvenIntegerThreshold, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({EvenIntegerThreshold, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({EvenIntegerThreshold, 1.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({EvenIntegerThreshold, 1.0},
|
||||
APFloat::rmNearestTiesToAway)
|
||||
.withRounded({EvenIntegerThreshold, 1.0},
|
||||
APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Ties (Midpoints)
|
||||
// Input: EvenIntegerThreshold-0.5
|
||||
TestCase({{EvenIntegerThreshold, -0.5}})
|
||||
.withRounded({EvenIntegerThreshold - 1.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({EvenIntegerThreshold - 1.0, 0.0},
|
||||
APFloat::rmTowardNegative)
|
||||
.withRounded({EvenIntegerThreshold, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({EvenIntegerThreshold, 0.0},
|
||||
APFloat::rmNearestTiesToAway)
|
||||
.withRounded({EvenIntegerThreshold, 0.0},
|
||||
APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: EvenIntegerThreshold+0.5
|
||||
TestCase({{EvenIntegerThreshold, 0.5}})
|
||||
.withRounded({EvenIntegerThreshold, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({EvenIntegerThreshold, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({EvenIntegerThreshold, 1.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({EvenIntegerThreshold, 1.0},
|
||||
APFloat::rmNearestTiesToAway)
|
||||
.withRounded({EvenIntegerThreshold, 0.0},
|
||||
APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: EvenIntegerThreshold+1.5
|
||||
TestCase({{EvenIntegerThreshold + 2.0, -0.5}})
|
||||
.withRounded({EvenIntegerThreshold, 1.0}, APFloat::rmTowardZero)
|
||||
.withRounded({EvenIntegerThreshold, 1.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({EvenIntegerThreshold + 2.0, 0.0},
|
||||
APFloat::rmTowardPositive)
|
||||
.withRounded({EvenIntegerThreshold + 2.0, 0.0},
|
||||
APFloat::rmNearestTiesToAway)
|
||||
.withRounded({EvenIntegerThreshold + 2.0, 0.0},
|
||||
APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: EvenIntegerThreshold+2.5
|
||||
TestCase({{EvenIntegerThreshold + 2.0, 0.5}})
|
||||
.withRounded({EvenIntegerThreshold + 2.0, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({EvenIntegerThreshold + 2.0, 0.0},
|
||||
APFloat::rmTowardNegative)
|
||||
.withRounded({EvenIntegerThreshold + 4.0, -1.0},
|
||||
APFloat::rmTowardPositive)
|
||||
.withRounded({EvenIntegerThreshold + 4.0, -1.0},
|
||||
APFloat::rmNearestTiesToAway)
|
||||
.withRounded({EvenIntegerThreshold + 2.0, 0.0},
|
||||
APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Near Ties
|
||||
// Input: EvenIntegerThreshold+0.5+HalfEps
|
||||
TestCase({{EvenIntegerThreshold, 0.5 + HalfEps}})
|
||||
.withRounded({EvenIntegerThreshold, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({EvenIntegerThreshold, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({EvenIntegerThreshold, 1.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({EvenIntegerThreshold, 1.0},
|
||||
APFloat::rmNearestTiesToAway)
|
||||
.withRounded({EvenIntegerThreshold, 1.0},
|
||||
APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: EvenIntegerThreshold+0.5-QuarterEps
|
||||
TestCase({{EvenIntegerThreshold, 0.5 - QuarterEps}})
|
||||
.withRounded({EvenIntegerThreshold, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({EvenIntegerThreshold, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({EvenIntegerThreshold, 1.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({EvenIntegerThreshold, 0.0},
|
||||
APFloat::rmNearestTiesToAway)
|
||||
.withRounded({EvenIntegerThreshold, 0.0},
|
||||
APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Canonical Boundary (Max lo for EvenIntegerThreshold is 1.0)
|
||||
// Input: EvenIntegerThreshold+1.0
|
||||
TestCase({{EvenIntegerThreshold, 1.0}})
|
||||
.withRounded({EvenIntegerThreshold, 1.0}, APFloat::rmTowardZero)
|
||||
.withRounded({EvenIntegerThreshold, 1.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({EvenIntegerThreshold, 1.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({EvenIntegerThreshold, 1.0},
|
||||
APFloat::rmNearestTiesToAway)
|
||||
.withRounded({EvenIntegerThreshold, 1.0},
|
||||
APFloat::rmNearestTiesToEven),
|
||||
|
||||
// 8. Special Values
|
||||
// Input: +Inf
|
||||
TestCase({{Inf, 0.0}})
|
||||
.withRounded({Inf, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({Inf, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({Inf, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({Inf, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({Inf, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: -Inf
|
||||
TestCase({{-Inf, 0.0}})
|
||||
.withRounded({-Inf, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({-Inf, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({-Inf, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({-Inf, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({-Inf, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
|
||||
// Input: NaN input hi. Expected output canonical (NaN, 0.0).
|
||||
TestCase({{QNaN, 0.0}})
|
||||
.withRounded({QNaN, 0.0}, APFloat::rmTowardZero)
|
||||
.withRounded({QNaN, 0.0}, APFloat::rmTowardNegative)
|
||||
.withRounded({QNaN, 0.0}, APFloat::rmTowardPositive)
|
||||
.withRounded({QNaN, 0.0}, APFloat::rmNearestTiesToAway)
|
||||
.withRounded({QNaN, 0.0}, APFloat::rmNearestTiesToEven),
|
||||
};
|
||||
return TestCases;
|
||||
}
|
||||
|
||||
class PPCDoubleDoubleRoundToIntegralValueTest
|
||||
: public testing::Test,
|
||||
public ::testing::WithParamInterface<
|
||||
PPCDoubleDoubleRoundToIntegralTestCase> {};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
PPCDoubleDoubleRoundToIntegralValueParamTests,
|
||||
PPCDoubleDoubleRoundToIntegralValueTest,
|
||||
::testing::ValuesIn(ppcDoubleDoubleRoundToIntegralTests()));
|
||||
|
||||
TEST_P(PPCDoubleDoubleRoundToIntegralValueTest,
|
||||
PPCDoubleDoubleRoundToIntegral) {
|
||||
const PPCDoubleDoubleRoundToIntegralTestCase TestCase = GetParam();
|
||||
const APFloat Input = makeDoubleAPFloat(TestCase.Input);
|
||||
EXPECT_FALSE(Input.isDenormal())
|
||||
<< TestCase.Input.Hi << " + " << TestCase.Input.Lo;
|
||||
for (size_t I = 0, E = std::size(TestCase.Rounded); I != E; ++I) {
|
||||
const auto RM = static_cast<APFloat::roundingMode>(I);
|
||||
const APFloat Expected = makeDoubleAPFloat(TestCase.Rounded[I]);
|
||||
EXPECT_FALSE(Expected.isDenormal())
|
||||
<< TestCase.Rounded[I].Hi << " + " << TestCase.Input.Lo;
|
||||
APFloat Actual = Input;
|
||||
Actual.roundToIntegral(RM);
|
||||
if (Actual.isNaN())
|
||||
EXPECT_TRUE(Actual.isNaN());
|
||||
else
|
||||
EXPECT_EQ(Actual.compare(Expected), APFloat::cmpEqual)
|
||||
<< "RM: " << RM << " Input.Hi: " << TestCase.Input.Hi
|
||||
<< " Input.Lo: " << TestCase.Input.Lo << " Actual: " << Actual
|
||||
<< " Expected.Hi: " << TestCase.Rounded[I].Hi
|
||||
<< " Expected.Lo: " << TestCase.Rounded[I].Lo
|
||||
<< " Expected: " << Expected;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5551,13 +6020,9 @@ TEST(APFloatTest, PPCDoubleDoubleNext) {
|
||||
return X;
|
||||
};
|
||||
|
||||
auto Zero = [] {
|
||||
return APFloat::getZero(APFloat::IEEEdouble());
|
||||
};
|
||||
auto Zero = [] { return APFloat::getZero(APFloat::IEEEdouble()); };
|
||||
|
||||
auto One = [] {
|
||||
return APFloat::getOne(APFloat::IEEEdouble());
|
||||
};
|
||||
auto One = [] { return APFloat::getOne(APFloat::IEEEdouble()); };
|
||||
|
||||
// 0x1p-1074
|
||||
auto MinSubnormal = [] {
|
||||
@ -5574,24 +6039,6 @@ TEST(APFloatTest, PPCDoubleDoubleNext) {
|
||||
// 2^-53
|
||||
auto EpsNeg = [&] { return scalbn(Eps(), -1, APFloat::rmNearestTiesToEven); };
|
||||
|
||||
auto MakeDoubleAPFloat = [](auto Hi, auto Lo) {
|
||||
APFloat HiFloat{APFloat::IEEEdouble(), APFloat::uninitialized};
|
||||
if constexpr (std::is_same_v<decltype(Hi), APFloat>) {
|
||||
HiFloat = Hi;
|
||||
} else {
|
||||
HiFloat = {APFloat::IEEEdouble(), Hi};
|
||||
}
|
||||
|
||||
APFloat LoFloat{APFloat::IEEEdouble(), APFloat::uninitialized};
|
||||
if constexpr (std::is_same_v<decltype(Lo), APFloat>) {
|
||||
LoFloat = Lo;
|
||||
} else {
|
||||
LoFloat = {APFloat::IEEEdouble(), Lo};
|
||||
}
|
||||
|
||||
APInt Bits = LoFloat.bitcastToAPInt().concat(HiFloat.bitcastToAPInt());
|
||||
return APFloat(APFloat::PPCDoubleDouble(), Bits);
|
||||
};
|
||||
APFloat Test(APFloat::PPCDoubleDouble(), APFloat::uninitialized);
|
||||
APFloat Expected(APFloat::PPCDoubleDouble(), APFloat::uninitialized);
|
||||
|
||||
@ -5719,55 +6166,55 @@ TEST(APFloatTest, PPCDoubleDoubleNext) {
|
||||
|
||||
// 2b. |hi| >= 2*DBL_MIN_NORMAL (DD precision > D precision)
|
||||
// Test at hi = 1.0, lo = 0.
|
||||
Test = MakeDoubleAPFloat(One(), Zero());
|
||||
Expected = MakeDoubleAPFloat(One(), MinSubnormal());
|
||||
Test = makeDoubleAPFloat(One(), Zero());
|
||||
Expected = makeDoubleAPFloat(One(), MinSubnormal());
|
||||
EXPECT_EQ(Test.next(false), APFloat::opOK);
|
||||
EXPECT_TRUE(Test.bitwiseIsEqual(Expected));
|
||||
|
||||
// Test at hi = -1.0. delta = 2^-1074 (positive, moving towards +Inf).
|
||||
Test = MakeDoubleAPFloat(-One(), Zero());
|
||||
Expected = MakeDoubleAPFloat(-One(), MinSubnormal());
|
||||
Test = makeDoubleAPFloat(-One(), Zero());
|
||||
Expected = makeDoubleAPFloat(-One(), MinSubnormal());
|
||||
EXPECT_EQ(Test.next(false), APFloat::opOK);
|
||||
EXPECT_TRUE(Test.bitwiseIsEqual(Expected));
|
||||
|
||||
// Testing the boundary where calculated delta equals DBL_TRUE_MIN.
|
||||
// Requires ilogb(hi) = E = -968.
|
||||
// delta = 2^(-968 - 106) = 2^-1074 = DBL_TRUE_MIN.
|
||||
Test = MakeDoubleAPFloat("0x1p-968", Zero());
|
||||
Expected = MakeDoubleAPFloat("0x1p-968", MinSubnormal());
|
||||
Test = makeDoubleAPFloat("0x1p-968", Zero());
|
||||
Expected = makeDoubleAPFloat("0x1p-968", MinSubnormal());
|
||||
EXPECT_EQ(Test.next(false), APFloat::opOK);
|
||||
EXPECT_TRUE(Test.bitwiseIsEqual(Expected));
|
||||
|
||||
// Testing below the boundary (E < -968). Delta clamps to DBL_TRUE_MIN.
|
||||
Test = MakeDoubleAPFloat("0x1p-969", Zero());
|
||||
Expected = MakeDoubleAPFloat("0x1p-969", MinSubnormal());
|
||||
Test = makeDoubleAPFloat("0x1p-969", Zero());
|
||||
Expected = makeDoubleAPFloat("0x1p-969", MinSubnormal());
|
||||
EXPECT_EQ(Test.next(false), APFloat::opOK);
|
||||
EXPECT_TRUE(Test.bitwiseIsEqual(Expected));
|
||||
|
||||
// 3. Standard Increment (No rollover)
|
||||
// hi=1.0, lo=2^-1074.
|
||||
Test = MakeDoubleAPFloat(One(), MinSubnormal());
|
||||
Expected = MakeDoubleAPFloat(One(), NextUp(MinSubnormal()));
|
||||
Test = makeDoubleAPFloat(One(), MinSubnormal());
|
||||
Expected = makeDoubleAPFloat(One(), NextUp(MinSubnormal()));
|
||||
EXPECT_EQ(Test.next(false), APFloat::opOK);
|
||||
EXPECT_TRUE(Test.bitwiseIsEqual(Expected));
|
||||
|
||||
// Incrementing negative lo.
|
||||
Test = MakeDoubleAPFloat(One(), -MinSubnormal());
|
||||
Expected = MakeDoubleAPFloat(One(), Zero());
|
||||
Test = makeDoubleAPFloat(One(), -MinSubnormal());
|
||||
Expected = makeDoubleAPFloat(One(), Zero());
|
||||
EXPECT_EQ(Test.next(false), APFloat::opOK);
|
||||
EXPECT_EQ(Test.compare(Expected), APFloat::cmpEqual);
|
||||
|
||||
// Crossing lo=0.
|
||||
Test = MakeDoubleAPFloat(One(), -MinSubnormal());
|
||||
Expected = MakeDoubleAPFloat(One(), Zero());
|
||||
Test = makeDoubleAPFloat(One(), -MinSubnormal());
|
||||
Expected = makeDoubleAPFloat(One(), Zero());
|
||||
EXPECT_EQ(Test.next(false), APFloat::opOK);
|
||||
EXPECT_EQ(Test.compare(Expected), APFloat::cmpEqual);
|
||||
|
||||
// 4. Rollover Cases around 1.0 (Positive hi)
|
||||
// hi=1.0, lo=nextDown(2^-53).
|
||||
Test = MakeDoubleAPFloat(One(), NextDown(EpsNeg()));
|
||||
Test = makeDoubleAPFloat(One(), NextDown(EpsNeg()));
|
||||
EXPECT_FALSE(Test.isDenormal());
|
||||
Expected = MakeDoubleAPFloat(One(), EpsNeg());
|
||||
Expected = makeDoubleAPFloat(One(), EpsNeg());
|
||||
EXPECT_FALSE(Test.isDenormal());
|
||||
EXPECT_EQ(Test.next(false), APFloat::opOK);
|
||||
EXPECT_TRUE(Test.bitwiseIsEqual(Expected));
|
||||
@ -5778,17 +6225,17 @@ TEST(APFloatTest, PPCDoubleDoubleNext) {
|
||||
// Can't naively TwoSum(0x1p+0, nextUp(0x1p-53)):
|
||||
// It gives {nextUp(0x1p+0), nextUp(nextUp(-0x1p-53))} but the next
|
||||
// number should be {nextUp(0x1p+0), nextUp(-0x1p-53)}.
|
||||
Test = MakeDoubleAPFloat(One(), EpsNeg());
|
||||
Test = makeDoubleAPFloat(One(), EpsNeg());
|
||||
EXPECT_FALSE(Test.isDenormal());
|
||||
Expected = MakeDoubleAPFloat(NextUp(One()), NextUp(-EpsNeg()));
|
||||
Expected = makeDoubleAPFloat(NextUp(One()), NextUp(-EpsNeg()));
|
||||
EXPECT_EQ(Test.next(false), APFloat::opOK);
|
||||
EXPECT_TRUE(Test.bitwiseIsEqual(Expected));
|
||||
EXPECT_FALSE(Test.isDenormal());
|
||||
|
||||
// hi = nextDown(1), lo = nextDown(0x1p-54)
|
||||
Test = MakeDoubleAPFloat(NextDown(One()), NextDown(APFloat(0x1p-54)));
|
||||
Test = makeDoubleAPFloat(NextDown(One()), NextDown(APFloat(0x1p-54)));
|
||||
EXPECT_FALSE(Test.isDenormal());
|
||||
Expected = MakeDoubleAPFloat(One(), APFloat(-0x1p-54));
|
||||
Expected = makeDoubleAPFloat(One(), APFloat(-0x1p-54));
|
||||
EXPECT_EQ(Test.next(false), APFloat::opOK);
|
||||
EXPECT_TRUE(Test.bitwiseIsEqual(Expected));
|
||||
EXPECT_FALSE(Test.isDenormal());
|
||||
@ -5796,26 +6243,26 @@ TEST(APFloatTest, PPCDoubleDoubleNext) {
|
||||
// 5. Negative Rollover (Moving towards Zero / +Inf)
|
||||
|
||||
// hi = -1, lo = nextDown(0x1p-54)
|
||||
Test = MakeDoubleAPFloat(APFloat(-1.0), NextDown(APFloat(0x1p-54)));
|
||||
Test = makeDoubleAPFloat(APFloat(-1.0), NextDown(APFloat(0x1p-54)));
|
||||
EXPECT_FALSE(Test.isDenormal());
|
||||
Expected = MakeDoubleAPFloat(APFloat(-1.0), APFloat(0x1p-54));
|
||||
Expected = makeDoubleAPFloat(APFloat(-1.0), APFloat(0x1p-54));
|
||||
EXPECT_EQ(Test.next(false), APFloat::opOK);
|
||||
EXPECT_TRUE(Test.bitwiseIsEqual(Expected));
|
||||
EXPECT_FALSE(Test.isDenormal());
|
||||
|
||||
// hi = -1, lo = 0x1p-54
|
||||
Test = MakeDoubleAPFloat(APFloat(-1.0), APFloat(0x1p-54));
|
||||
Test = makeDoubleAPFloat(APFloat(-1.0), APFloat(0x1p-54));
|
||||
EXPECT_FALSE(Test.isDenormal());
|
||||
Expected =
|
||||
MakeDoubleAPFloat(NextUp(APFloat(-1.0)), NextUp(APFloat(-0x1p-54)));
|
||||
makeDoubleAPFloat(NextUp(APFloat(-1.0)), NextUp(APFloat(-0x1p-54)));
|
||||
EXPECT_EQ(Test.next(false), APFloat::opOK);
|
||||
EXPECT_TRUE(Test.bitwiseIsEqual(Expected));
|
||||
EXPECT_FALSE(Test.isDenormal());
|
||||
|
||||
// 6. Rollover across Power of 2 boundary (Exponent change)
|
||||
Test = MakeDoubleAPFloat(NextDown(APFloat(2.0)), NextDown(EpsNeg()));
|
||||
Test = makeDoubleAPFloat(NextDown(APFloat(2.0)), NextDown(EpsNeg()));
|
||||
EXPECT_FALSE(Test.isDenormal());
|
||||
Expected = MakeDoubleAPFloat(APFloat(2.0), -EpsNeg());
|
||||
Expected = makeDoubleAPFloat(APFloat(2.0), -EpsNeg());
|
||||
EXPECT_EQ(Test.next(false), APFloat::opOK);
|
||||
EXPECT_TRUE(Test.bitwiseIsEqual(Expected));
|
||||
EXPECT_FALSE(Test.isDenormal());
|
||||
|
Loading…
x
Reference in New Issue
Block a user