[flang] More real work. All ops, rounding modes, and flags good except for division.
Original-commit: flang-compiler/f18@ea697295db Reviewed-on: https://github.com/flang-compiler/f18/pull/101 Tree-same-pre-rewrite: false
This commit is contained in:
parent
fab448de59
commit
52ef92b513
|
|
@ -267,8 +267,11 @@ public:
|
||||||
return y.Add(*this, rounding);
|
return y.Add(*this, rounding);
|
||||||
}
|
}
|
||||||
if (order == Ordering::Equal) {
|
if (order == Ordering::Equal) {
|
||||||
// x + (-x) -> +0.0, never -0.0
|
// x + (-x) -> +0.0 unless rounding is directed downwards
|
||||||
return {};
|
if (rounding == Rounding::Down) {
|
||||||
|
result.value.Normalize(true, 0, Fraction{}, rounding); // -0.0
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Our exponent is greater than y's, or the exponents match and y is not
|
// Our exponent is greater than y's, or the exponents match and y is not
|
||||||
|
|
@ -296,8 +299,8 @@ public:
|
||||||
fraction = fraction.SHIFTR(1).IBSET(fraction.bits - 1);
|
fraction = fraction.SHIFTR(1).IBSET(fraction.bits - 1);
|
||||||
++exponent;
|
++exponent;
|
||||||
}
|
}
|
||||||
result.flags |=
|
result.flags |= result.value.Normalize(
|
||||||
result.value.Normalize(isNegative, exponent, fraction, &roundingBits);
|
isNegative, exponent, fraction, rounding, &roundingBits);
|
||||||
result.flags |= result.value.Round(rounding, roundingBits);
|
result.flags |= result.value.Round(rounding, roundingBits);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -312,7 +315,9 @@ public:
|
||||||
ValueWithRealFlags<Real> result;
|
ValueWithRealFlags<Real> result;
|
||||||
if (IsNotANumber() || y.IsNotANumber()) {
|
if (IsNotANumber() || y.IsNotANumber()) {
|
||||||
result.value.word_ = NaNWord(); // NaN * x -> NaN
|
result.value.word_ = NaNWord(); // NaN * x -> NaN
|
||||||
|
if (IsSignalingNaN() || y.IsSignalingNaN()) {
|
||||||
result.flags.set(RealFlag::InvalidArgument);
|
result.flags.set(RealFlag::InvalidArgument);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
bool isNegative{IsNegative() != y.IsNegative()};
|
bool isNegative{IsNegative() != y.IsNegative()};
|
||||||
if (IsInfinite() || y.IsInfinite()) {
|
if (IsInfinite() || y.IsInfinite()) {
|
||||||
|
|
@ -338,7 +343,10 @@ public:
|
||||||
if (rshift >= product.upper.bits + product.lower.bits) {
|
if (rshift >= product.upper.bits + product.lower.bits) {
|
||||||
sticky = !product.lower.IsZero() || !product.upper.IsZero();
|
sticky = !product.lower.IsZero() || !product.upper.IsZero();
|
||||||
} else if (rshift >= product.lower.bits) {
|
} else if (rshift >= product.lower.bits) {
|
||||||
sticky = !product.lower.IsZero();
|
sticky = !product.lower.IsZero() ||
|
||||||
|
!product.upper
|
||||||
|
.IAND(product.upper.MASKR(rshift - product.lower.bits))
|
||||||
|
.IsZero();
|
||||||
} else {
|
} else {
|
||||||
sticky = !product.lower.IAND(product.lower.MASKR(rshift)).IsZero();
|
sticky = !product.lower.IAND(product.lower.MASKR(rshift)).IsZero();
|
||||||
}
|
}
|
||||||
|
|
@ -359,10 +367,14 @@ public:
|
||||||
exponent -= lshift;
|
exponent -= lshift;
|
||||||
product.upper = product.upper.DSHIFTL(product.lower, lshift);
|
product.upper = product.upper.DSHIFTL(product.lower, lshift);
|
||||||
product.lower = product.lower.SHIFTL(lshift);
|
product.lower = product.lower.SHIFTL(lshift);
|
||||||
RoundingBits roundingBits{product.lower, product.upper.bits};
|
RoundingBits roundingBits{product.lower, product.lower.bits};
|
||||||
result.flags |= result.value.Normalize(
|
result.flags |= result.value.Normalize(
|
||||||
isNegative, exponent, product.upper, &roundingBits);
|
isNegative, exponent, product.upper, rounding, &roundingBits);
|
||||||
result.flags |= result.value.Round(rounding, roundingBits);
|
result.flags |= result.value.Round(rounding, roundingBits);
|
||||||
|
if (result.flags.test(RealFlag::Inexact) &&
|
||||||
|
result.value.Exponent() == 0) {
|
||||||
|
result.flags.set(RealFlag::Underflow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -514,9 +526,19 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr RealFlags Normalize(bool negative, std::uint64_t exponent,
|
constexpr RealFlags Normalize(bool negative, std::uint64_t exponent,
|
||||||
const Fraction &fraction, RoundingBits *roundingBits = nullptr) {
|
const Fraction &fraction, Rounding rounding = Rounding::TiesToEven,
|
||||||
|
RoundingBits *roundingBits = nullptr) {
|
||||||
if (exponent >= maxExponent) {
|
if (exponent >= maxExponent) {
|
||||||
|
if (rounding == Rounding::TiesToEven ||
|
||||||
|
rounding == Rounding::TiesAwayFromZero ||
|
||||||
|
(rounding == Rounding::Up && !negative) ||
|
||||||
|
(rounding == Rounding::Down && negative)) {
|
||||||
word_ = Word{maxExponent}.SHIFTL(significandBits); // Inf
|
word_ = Word{maxExponent}.SHIFTL(significandBits); // Inf
|
||||||
|
} else {
|
||||||
|
// directed rounding: round to largest finite value rather than infinity
|
||||||
|
// (x86 does this, not sure whether it's standard or not)
|
||||||
|
word_ = Word{word_.MASKR(word_.bits - 1)}.IBCLR(significandBits);
|
||||||
|
}
|
||||||
if (negative) {
|
if (negative) {
|
||||||
word_ = word_.IBSET(bits - 1);
|
word_ = word_.IBSET(bits - 1);
|
||||||
}
|
}
|
||||||
|
|
@ -608,7 +630,7 @@ extern template class Real<Integer<32>, 24>;
|
||||||
using RealKind8 = Real<Integer<64>, 53>;
|
using RealKind8 = Real<Integer<64>, 53>;
|
||||||
extern template class Real<Integer<64>, 53>;
|
extern template class Real<Integer<64>, 53>;
|
||||||
|
|
||||||
using RealKind10 = Real<Integer<80>, 64, false>; // 80387
|
using RealKind10 = Real<Integer<80>, 64, false>; // 80387 extended precision
|
||||||
extern template class Real<Integer<80>, 64, false>;
|
extern template class Real<Integer<80>, 64, false>;
|
||||||
|
|
||||||
using RealKind16 = Real<Integer<128>, 112>;
|
using RealKind16 = Real<Integer<128>, 112>;
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ void ScopedHostFloatingPointEnvironment::ClearFlags() const {
|
||||||
feclearexcept(FE_ALL_EXCEPT);
|
feclearexcept(FE_ALL_EXCEPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
RealFlags ScopedHostFloatingPointEnvironment::CurrentFlags() const {
|
RealFlags ScopedHostFloatingPointEnvironment::CurrentFlags() {
|
||||||
int exceptions = fetestexcept(FE_ALL_EXCEPT);
|
int exceptions = fetestexcept(FE_ALL_EXCEPT);
|
||||||
RealFlags flags;
|
RealFlags flags;
|
||||||
if (exceptions & FE_INVALID) {
|
if (exceptions & FE_INVALID) {
|
||||||
|
|
@ -83,3 +83,16 @@ RealFlags ScopedHostFloatingPointEnvironment::CurrentFlags() const {
|
||||||
}
|
}
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScopedHostFloatingPointEnvironment::SetRounding(Rounding rounding) {
|
||||||
|
switch (rounding) {
|
||||||
|
case Rounding::TiesToEven: fesetround(FE_TONEAREST); break;
|
||||||
|
case Rounding::ToZero: fesetround(FE_TOWARDZERO); break;
|
||||||
|
case Rounding::Up: fesetround(FE_UPWARD); break;
|
||||||
|
case Rounding::Down: fesetround(FE_DOWNWARD); break;
|
||||||
|
case Rounding::TiesAwayFromZero:
|
||||||
|
std::fprintf(stderr, "SetRounding: TiesAwayFromZero not available");
|
||||||
|
std::abort();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
#include <fenv.h>
|
#include <fenv.h>
|
||||||
|
|
||||||
using Fortran::evaluate::RealFlags;
|
using Fortran::evaluate::RealFlags;
|
||||||
|
using Fortran::evaluate::Rounding;
|
||||||
|
|
||||||
class ScopedHostFloatingPointEnvironment {
|
class ScopedHostFloatingPointEnvironment {
|
||||||
public:
|
public:
|
||||||
|
|
@ -26,7 +27,8 @@ public:
|
||||||
bool flushDenormalResultsToZero = false);
|
bool flushDenormalResultsToZero = false);
|
||||||
~ScopedHostFloatingPointEnvironment();
|
~ScopedHostFloatingPointEnvironment();
|
||||||
void ClearFlags() const;
|
void ClearFlags() const;
|
||||||
RealFlags CurrentFlags() const;
|
static RealFlags CurrentFlags();
|
||||||
|
static void SetRounding(Rounding rounding);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
fenv_t originalFenv_;
|
fenv_t originalFenv_;
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
using namespace Fortran::evaluate;
|
using namespace Fortran::evaluate;
|
||||||
|
|
||||||
template<typename R> void tests() {
|
template<typename R> void basicTests(int rm, Rounding rounding) {
|
||||||
char desc[64];
|
char desc[64];
|
||||||
using Word = typename R::Word;
|
using Word = typename R::Word;
|
||||||
std::snprintf(
|
std::snprintf(
|
||||||
|
|
@ -99,51 +99,52 @@ template<typename R> void tests() {
|
||||||
TEST(inf.Compare(negInf) == Relation::Greater)(desc);
|
TEST(inf.Compare(negInf) == Relation::Greater)(desc);
|
||||||
TEST(negInf.Compare(negInf) == Relation::Equal)(desc);
|
TEST(negInf.Compare(negInf) == Relation::Equal)(desc);
|
||||||
for (std::uint64_t j{0}; j < 63; ++j) {
|
for (std::uint64_t j{0}; j < 63; ++j) {
|
||||||
|
char ldesc[128];
|
||||||
std::uint64_t x{1};
|
std::uint64_t x{1};
|
||||||
x <<= j;
|
x <<= j;
|
||||||
|
std::snprintf(ldesc, sizeof ldesc, "%s j=%d x=0x%llx rm=%d", desc,
|
||||||
|
static_cast<int>(j), static_cast<unsigned long long>(x), rm);
|
||||||
Integer<64> ix{x};
|
Integer<64> ix{x};
|
||||||
TEST(!ix.IsNegative())("%s,%d,0x%llx", desc, j, x);
|
TEST(!ix.IsNegative())(ldesc);
|
||||||
MATCH(x, ix.ToUInt64())("%s,%d,0x%llx", desc, j, x);
|
MATCH(x, ix.ToUInt64())(ldesc);
|
||||||
vr = R::ConvertSigned(ix);
|
vr = R::ConvertSigned(ix, rounding);
|
||||||
TEST(!vr.value.IsNegative())("%s,%d,0x%llx", desc, j, x);
|
TEST(!vr.value.IsNegative())(ldesc);
|
||||||
TEST(!vr.value.IsNotANumber())("%s,%d,0x%llx", desc, j, x);
|
TEST(!vr.value.IsNotANumber())(ldesc);
|
||||||
TEST(!vr.value.IsZero())("%s,%d,0x%llx", desc, j, x);
|
TEST(!vr.value.IsZero())(ldesc);
|
||||||
auto ivf = vr.value.template ToInteger<Integer<64>>();
|
auto ivf = vr.value.template ToInteger<Integer<64>>();
|
||||||
if (j > (maxExponent / 2)) {
|
if (j > (maxExponent / 2)) {
|
||||||
TEST(vr.flags.test(RealFlag::Overflow))(desc);
|
TEST(vr.flags.test(RealFlag::Overflow))(ldesc);
|
||||||
TEST(vr.value.IsInfinite())("%s,%d,0x%llx", desc, j, x);
|
TEST(vr.value.IsInfinite())(ldesc);
|
||||||
TEST(ivf.flags.test(RealFlag::Overflow))("%s,%d,0x%llx", desc, j, x);
|
TEST(ivf.flags.test(RealFlag::Overflow))(ldesc);
|
||||||
MATCH(0x7fffffffffffffff, ivf.value.ToUInt64())
|
MATCH(0x7fffffffffffffff, ivf.value.ToUInt64())(ldesc);
|
||||||
("%s,%d,0x%llx", desc, j, x);
|
|
||||||
} else {
|
} else {
|
||||||
TEST(vr.flags.empty())(desc);
|
TEST(vr.flags.empty())(ldesc);
|
||||||
TEST(!vr.value.IsInfinite())("%s,%d,0x%llx", desc, j, x);
|
TEST(!vr.value.IsInfinite())(ldesc);
|
||||||
TEST(ivf.flags.empty())("%s,%d,0x%llx", desc, j, x);
|
TEST(ivf.flags.empty())(ldesc);
|
||||||
MATCH(x, ivf.value.ToUInt64())("%s,%d,0x%llx", desc, j, x);
|
MATCH(x, ivf.value.ToUInt64())(ldesc);
|
||||||
}
|
}
|
||||||
ix = ix.Negate().value;
|
ix = ix.Negate().value;
|
||||||
TEST(ix.IsNegative())("%s,%d,0x%llx", desc, j, x);
|
TEST(ix.IsNegative())(ldesc);
|
||||||
x = -x;
|
x = -x;
|
||||||
std::int64_t nx = x;
|
std::int64_t nx = x;
|
||||||
MATCH(x, ix.ToUInt64())("%s,%d,0x%llx", desc, j, x);
|
MATCH(x, ix.ToUInt64())(ldesc);
|
||||||
MATCH(nx, ix.ToInt64())("%s,%d,0x%llx", desc, j, x);
|
MATCH(nx, ix.ToInt64())(ldesc);
|
||||||
vr = R::ConvertSigned(ix);
|
vr = R::ConvertSigned(ix);
|
||||||
TEST(vr.value.IsNegative())("%s,%d,0x%llx", desc, j, x);
|
TEST(vr.value.IsNegative())(ldesc);
|
||||||
TEST(!vr.value.IsNotANumber())("%s,%d,0x%llx", desc, j, x);
|
TEST(!vr.value.IsNotANumber())(ldesc);
|
||||||
TEST(!vr.value.IsZero())("%s,%d,0x%llx", desc, j, x);
|
TEST(!vr.value.IsZero())(ldesc);
|
||||||
ivf = vr.value.template ToInteger<Integer<64>>();
|
ivf = vr.value.template ToInteger<Integer<64>>();
|
||||||
if (j > (maxExponent / 2)) {
|
if (j > (maxExponent / 2)) {
|
||||||
TEST(vr.flags.test(RealFlag::Overflow))(desc);
|
TEST(vr.flags.test(RealFlag::Overflow))(ldesc);
|
||||||
TEST(vr.value.IsInfinite())("%s,%d,0x%llx", desc, j, x);
|
TEST(vr.value.IsInfinite())(ldesc);
|
||||||
TEST(ivf.flags.test(RealFlag::Overflow))("%s,%d,0x%llx", desc, j, x);
|
TEST(ivf.flags.test(RealFlag::Overflow))(ldesc);
|
||||||
MATCH(0x8000000000000000, ivf.value.ToUInt64())
|
MATCH(0x8000000000000000, ivf.value.ToUInt64())(ldesc);
|
||||||
("%s,%d,0x%llx", desc, j, x);
|
|
||||||
} else {
|
} else {
|
||||||
TEST(vr.flags.empty())(desc);
|
TEST(vr.flags.empty())(ldesc);
|
||||||
TEST(!vr.value.IsInfinite())("%s,%d,0x%llx", desc, j, x);
|
TEST(!vr.value.IsInfinite())(ldesc);
|
||||||
TEST(ivf.flags.empty())("%s,%d,0x%llx", desc, j, x);
|
TEST(ivf.flags.empty())(ldesc);
|
||||||
MATCH(x, ivf.value.ToUInt64())("%s,%d,0x%llx", desc, j, x);
|
MATCH(x, ivf.value.ToUInt64())(ldesc);
|
||||||
MATCH(nx, ivf.value.ToInt64())("%s,%d,0x%llx", desc, j, x);
|
MATCH(nx, ivf.value.ToInt64())(ldesc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -183,12 +184,41 @@ std::uint32_t FlagsToBits(const RealFlags &flags) {
|
||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
void subset32bit() {
|
void inttest(std::int64_t x, int pass, Rounding rounding) {
|
||||||
union {
|
union {
|
||||||
std::uint32_t u32;
|
std::uint32_t u32;
|
||||||
float f;
|
float f;
|
||||||
} u;
|
} u;
|
||||||
ScopedHostFloatingPointEnvironment fpenv;
|
ScopedHostFloatingPointEnvironment fpenv;
|
||||||
|
Integer<64> ix{x};
|
||||||
|
ValueWithRealFlags<RealKind4> real;
|
||||||
|
real = real.value.ConvertSigned(ix, rounding);
|
||||||
|
fpenv.ClearFlags();
|
||||||
|
float fcheck = x; // TODO unsigned too
|
||||||
|
auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
|
||||||
|
u.f = fcheck;
|
||||||
|
std::uint32_t rcheck{NormalizeNaN(u.u32)};
|
||||||
|
std::uint32_t check = real.value.RawBits().ToUInt64();
|
||||||
|
MATCH(rcheck, check)("%d 0x%llx", pass, x);
|
||||||
|
MATCH(actualFlags, FlagsToBits(real.flags))("%d 0x%llx", pass, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void subset32bit(int pass, Rounding rounding) {
|
||||||
|
for (int j{0}; j < 63; ++j) {
|
||||||
|
std::int64_t x{1};
|
||||||
|
x <<= j;
|
||||||
|
inttest(x, pass, rounding);
|
||||||
|
inttest(-x, pass, rounding);
|
||||||
|
}
|
||||||
|
inttest(0, pass, rounding);
|
||||||
|
inttest(static_cast<std::int64_t>(0x8000000000000000), pass, rounding);
|
||||||
|
|
||||||
|
union {
|
||||||
|
std::uint32_t u32;
|
||||||
|
float f;
|
||||||
|
} u;
|
||||||
|
ScopedHostFloatingPointEnvironment fpenv;
|
||||||
|
|
||||||
for (std::uint32_t j{0}; j < 8192; ++j) {
|
for (std::uint32_t j{0}; j < 8192; ++j) {
|
||||||
std::uint32_t rj{MakeReal(j)};
|
std::uint32_t rj{MakeReal(j)};
|
||||||
u.u32 = rj;
|
u.u32 = rj;
|
||||||
|
|
@ -200,51 +230,71 @@ void subset32bit() {
|
||||||
float fk{u.f};
|
float fk{u.f};
|
||||||
RealKind4 y{Integer<32>{std::uint64_t{rk}}};
|
RealKind4 y{Integer<32>{std::uint64_t{rk}}};
|
||||||
{
|
{
|
||||||
ValueWithRealFlags<RealKind4> sum{x.Add(y)};
|
ValueWithRealFlags<RealKind4> sum{x.Add(y, rounding)};
|
||||||
fpenv.ClearFlags();
|
fpenv.ClearFlags();
|
||||||
float fcheck{fj + fk};
|
float fcheck{fj + fk};
|
||||||
auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
|
auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
|
||||||
u.f = fcheck;
|
u.f = fcheck;
|
||||||
std::uint32_t rcheck{NormalizeNaN(u.u32)};
|
std::uint32_t rcheck{NormalizeNaN(u.u32)};
|
||||||
std::uint32_t check = sum.value.RawBits().ToUInt64();
|
std::uint32_t check = sum.value.RawBits().ToUInt64();
|
||||||
MATCH(rcheck, check)("0x%x + 0x%x", rj, rk);
|
MATCH(rcheck, check)("%d 0x%x + 0x%x", pass, rj, rk);
|
||||||
MATCH(actualFlags, FlagsToBits(sum.flags))("0x%x + 0x%x", rj, rk);
|
MATCH(actualFlags, FlagsToBits(sum.flags))
|
||||||
|
("%d 0x%x + 0x%x", pass, rj, rk);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
ValueWithRealFlags<RealKind4> diff{x.Subtract(y)};
|
ValueWithRealFlags<RealKind4> diff{x.Subtract(y, rounding)};
|
||||||
|
fpenv.ClearFlags();
|
||||||
float fcheck{fj - fk};
|
float fcheck{fj - fk};
|
||||||
|
auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
|
||||||
u.f = fcheck;
|
u.f = fcheck;
|
||||||
std::uint32_t rcheck{NormalizeNaN(u.u32)};
|
std::uint32_t rcheck{NormalizeNaN(u.u32)};
|
||||||
std::uint32_t check = diff.value.RawBits().ToUInt64();
|
std::uint32_t check = diff.value.RawBits().ToUInt64();
|
||||||
MATCH(rcheck, check)("0x%x - 0x%x", rj, rk);
|
MATCH(rcheck, check)("%d 0x%x - 0x%x", pass, rj, rk);
|
||||||
|
MATCH(actualFlags, FlagsToBits(diff.flags))
|
||||||
|
("%d 0x%x - 0x%x", pass, rj, rk);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
ValueWithRealFlags<RealKind4> prod{x.Multiply(y)};
|
ValueWithRealFlags<RealKind4> prod{x.Multiply(y, rounding)};
|
||||||
|
fpenv.ClearFlags();
|
||||||
float fcheck{fj * fk};
|
float fcheck{fj * fk};
|
||||||
|
auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
|
||||||
u.f = fcheck;
|
u.f = fcheck;
|
||||||
std::uint32_t rcheck{NormalizeNaN(u.u32)};
|
std::uint32_t rcheck{NormalizeNaN(u.u32)};
|
||||||
std::uint32_t check = prod.value.RawBits().ToUInt64();
|
std::uint32_t check = prod.value.RawBits().ToUInt64();
|
||||||
MATCH(rcheck, check)("0x%x * 0x%x", rj, rk);
|
MATCH(rcheck, check)("%d 0x%x * 0x%x", pass, rj, rk);
|
||||||
|
MATCH(actualFlags, FlagsToBits(prod.flags))
|
||||||
|
("%d 0x%x * 0x%x -> 0x%x", pass, rj, rk, rcheck);
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
{ ValueWithRealFlags<RealKind4> quot{x.Divide(y)};
|
{ ValueWithRealFlags<RealKind4> quot{x.Divide(y, rounding)};
|
||||||
float fcheck{fj * fk};
|
fpenv.ClearFlags();
|
||||||
|
float fcheck{fj / fk};
|
||||||
|
auto actualFlags{FlagsToBits(fpenv.CurrentFlags())};
|
||||||
u.f = fcheck;
|
u.f = fcheck;
|
||||||
std::uint32_t rcheck{NormalizeNaN(u.u32)};
|
std::uint32_t rcheck{NormalizeNaN(u.u32)};
|
||||||
std::uint32_t check = quot.value.RawBits().ToUInt64();
|
std::uint32_t check = quot.value.RawBits().ToUInt64();
|
||||||
MATCH(rcheck, check)("0x%x / 0x%x", rj, rk);
|
MATCH(rcheck, check)("%d 0x%x / 0x%x", pass, rj, rk);
|
||||||
|
MATCH(actualFlags, FlagsToBits(quot.flags))("%d 0x%x / 0x%x", pass, rj, rk);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
void roundTest(int rm, Rounding rounding) {
|
||||||
tests<RealKind2>();
|
basicTests<RealKind2>(rm, rounding);
|
||||||
tests<RealKind4>();
|
basicTests<RealKind4>(rm, rounding);
|
||||||
tests<RealKind8>();
|
basicTests<RealKind8>(rm, rounding);
|
||||||
tests<RealKind10>();
|
basicTests<RealKind10>(rm, rounding);
|
||||||
tests<RealKind16>();
|
basicTests<RealKind16>(rm, rounding);
|
||||||
subset32bit(); // TODO rounding modes
|
ScopedHostFloatingPointEnvironment::SetRounding(rounding);
|
||||||
return testing::Complete();
|
subset32bit(rm, rounding);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
roundTest(0, Rounding::TiesToEven);
|
||||||
|
roundTest(1, Rounding::ToZero);
|
||||||
|
roundTest(2, Rounding::Up);
|
||||||
|
roundTest(3, Rounding::Down);
|
||||||
|
// TODO: how to test Rounding::TiesAwayFromZero on x86?
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue