1ee5fa1f2SLuke Ireland #include "fp-testing.h" 2ee5fa1f2SLuke Ireland #include "testing.h" 3ee5fa1f2SLuke Ireland #include "flang/Evaluate/type.h" 48670e499SCaroline Concatto #include "llvm/Support/raw_ostream.h" 5ee5fa1f2SLuke Ireland #include <cmath> 6ee5fa1f2SLuke Ireland #include <cstdio> 7ee5fa1f2SLuke Ireland #include <cstdlib> 8ee5fa1f2SLuke Ireland #include <type_traits> 9ee5fa1f2SLuke Ireland 10ee5fa1f2SLuke Ireland using namespace Fortran::evaluate; 11ee5fa1f2SLuke Ireland using namespace Fortran::common; 12ee5fa1f2SLuke Ireland 13ee5fa1f2SLuke Ireland using Real2 = Scalar<Type<TypeCategory::Real, 2>>; 14ee5fa1f2SLuke Ireland using Real3 = Scalar<Type<TypeCategory::Real, 3>>; 15ee5fa1f2SLuke Ireland using Real4 = Scalar<Type<TypeCategory::Real, 4>>; 16ee5fa1f2SLuke Ireland using Real8 = Scalar<Type<TypeCategory::Real, 8>>; 1758b51492Smadanial0 #ifdef __x86_64__ 18ee5fa1f2SLuke Ireland using Real10 = Scalar<Type<TypeCategory::Real, 10>>; 1958b51492Smadanial0 #endif 20ee5fa1f2SLuke Ireland using Real16 = Scalar<Type<TypeCategory::Real, 16>>; 21ee5fa1f2SLuke Ireland using Integer4 = Scalar<Type<TypeCategory::Integer, 4>>; 22ee5fa1f2SLuke Ireland using Integer8 = Scalar<Type<TypeCategory::Integer, 8>>; 23ee5fa1f2SLuke Ireland 24ee5fa1f2SLuke Ireland void dumpTest() { 25ee5fa1f2SLuke Ireland struct { 26ee5fa1f2SLuke Ireland std::uint64_t raw; 27ee5fa1f2SLuke Ireland const char *expected; 28ee5fa1f2SLuke Ireland } table[] = { 29ee5fa1f2SLuke Ireland {0x7f876543, "NaN0x7f876543"}, 30ee5fa1f2SLuke Ireland {0x7f800000, "Inf"}, 31ee5fa1f2SLuke Ireland {0xff800000, "-Inf"}, 32ee5fa1f2SLuke Ireland {0x00000000, "0.0"}, 33ee5fa1f2SLuke Ireland {0x80000000, "-0.0"}, 34ee5fa1f2SLuke Ireland {0x3f800000, "0x1.0p0"}, 35ee5fa1f2SLuke Ireland {0xbf800000, "-0x1.0p0"}, 36ee5fa1f2SLuke Ireland {0x40000000, "0x1.0p1"}, 37ee5fa1f2SLuke Ireland {0x3f000000, "0x1.0p-1"}, 38ee5fa1f2SLuke Ireland {0x7f7fffff, "0x1.fffffep127"}, 39ee5fa1f2SLuke Ireland {0x00800000, "0x1.0p-126"}, 400ff32224SPeixinQiao {0x00400000, "0x0.8p-126"}, 410ff32224SPeixinQiao {0x00000001, "0x0.000002p-126"}, 42ee5fa1f2SLuke Ireland {0, nullptr}, 43ee5fa1f2SLuke Ireland }; 44ee5fa1f2SLuke Ireland for (int j{0}; table[j].expected != nullptr; ++j) { 45ee5fa1f2SLuke Ireland TEST(Real4{Integer4{table[j].raw}}.DumpHexadecimal() == table[j].expected) 46ee5fa1f2SLuke Ireland ("%d", j); 47ee5fa1f2SLuke Ireland } 48ee5fa1f2SLuke Ireland } 49ee5fa1f2SLuke Ireland 50ee5fa1f2SLuke Ireland template <typename R> void basicTests(int rm, Rounding rounding) { 51ee5fa1f2SLuke Ireland static constexpr int kind{R::bits / 8}; 52ee5fa1f2SLuke Ireland char desc[64]; 53ee5fa1f2SLuke Ireland using Word = typename R::Word; 54ee5fa1f2SLuke Ireland std::snprintf(desc, sizeof desc, "bits=%d, le=%d, kind=%d", R::bits, 55ee5fa1f2SLuke Ireland Word::littleEndian, kind); 56ee5fa1f2SLuke Ireland R zero; 57ee5fa1f2SLuke Ireland TEST(!zero.IsNegative())(desc); 58ee5fa1f2SLuke Ireland TEST(!zero.IsNotANumber())(desc); 59ee5fa1f2SLuke Ireland TEST(!zero.IsInfinite())(desc); 60ee5fa1f2SLuke Ireland TEST(zero.IsZero())(desc); 61ee5fa1f2SLuke Ireland MATCH(0, zero.Exponent())(desc); 62ee5fa1f2SLuke Ireland TEST(zero.RawBits().IsZero())(desc); 63ee5fa1f2SLuke Ireland MATCH(0, zero.RawBits().ToUInt64())(desc); 64ee5fa1f2SLuke Ireland TEST(zero.ABS().RawBits().IsZero())(desc); 65ee5fa1f2SLuke Ireland TEST(zero.Negate().RawBits().IEOR(Word::MASKL(1)).IsZero())(desc); 66ee5fa1f2SLuke Ireland TEST(zero.Compare(zero) == Relation::Equal)(desc); 67ee5fa1f2SLuke Ireland R minusZero{Word{std::uint64_t{1}}.SHIFTL(R::bits - 1)}; 68ee5fa1f2SLuke Ireland TEST(minusZero.IsNegative())(desc); 69ee5fa1f2SLuke Ireland TEST(!minusZero.IsNotANumber())(desc); 70ee5fa1f2SLuke Ireland TEST(!minusZero.IsInfinite())(desc); 71ee5fa1f2SLuke Ireland TEST(minusZero.IsZero())(desc); 72ee5fa1f2SLuke Ireland TEST(minusZero.ABS().RawBits().IsZero())(desc); 73ee5fa1f2SLuke Ireland TEST(minusZero.Negate().RawBits().IsZero())(desc); 74ee5fa1f2SLuke Ireland MATCH(0, minusZero.Exponent())(desc); 75ee5fa1f2SLuke Ireland MATCH(0, minusZero.RawBits().LEADZ())(desc); 76ee5fa1f2SLuke Ireland MATCH(1, minusZero.RawBits().POPCNT())(desc); 77ee5fa1f2SLuke Ireland TEST(minusZero.Compare(minusZero) == Relation::Equal)(desc); 78ee5fa1f2SLuke Ireland TEST(zero.Compare(minusZero) == Relation::Equal)(desc); 79ee5fa1f2SLuke Ireland ValueWithRealFlags<R> vr; 80ee5fa1f2SLuke Ireland MATCH(0, vr.value.RawBits().ToUInt64())(desc); 81ee5fa1f2SLuke Ireland TEST(vr.flags.empty())(desc); 82ee5fa1f2SLuke Ireland R nan{Word{std::uint64_t{1}} 83ee5fa1f2SLuke Ireland .SHIFTL(R::bits) 84ee5fa1f2SLuke Ireland .SubtractSigned(Word{std::uint64_t{1}}) 85ee5fa1f2SLuke Ireland .value}; 86ee5fa1f2SLuke Ireland MATCH(R::bits, nan.RawBits().POPCNT())(desc); 87ee5fa1f2SLuke Ireland TEST(!nan.IsNegative())(desc); 88ee5fa1f2SLuke Ireland TEST(nan.IsNotANumber())(desc); 89ee5fa1f2SLuke Ireland TEST(!nan.IsInfinite())(desc); 90ee5fa1f2SLuke Ireland TEST(!nan.IsZero())(desc); 91ee5fa1f2SLuke Ireland TEST(zero.Compare(nan) == Relation::Unordered)(desc); 92ee5fa1f2SLuke Ireland TEST(minusZero.Compare(nan) == Relation::Unordered)(desc); 93ee5fa1f2SLuke Ireland TEST(nan.Compare(zero) == Relation::Unordered)(desc); 94ee5fa1f2SLuke Ireland TEST(nan.Compare(minusZero) == Relation::Unordered)(desc); 95ee5fa1f2SLuke Ireland TEST(nan.Compare(nan) == Relation::Unordered)(desc); 96ee5fa1f2SLuke Ireland int significandBits{R::binaryPrecision - R::isImplicitMSB}; 97ee5fa1f2SLuke Ireland int exponentBits{R::bits - significandBits - 1}; 98ee5fa1f2SLuke Ireland std::uint64_t maxExponent{(std::uint64_t{1} << exponentBits) - 1}; 99ee5fa1f2SLuke Ireland MATCH(nan.Exponent(), maxExponent)(desc); 1000e05ab67SPeter Klausler Word infWord{Word{maxExponent}.SHIFTL(significandBits)}; 1010e05ab67SPeter Klausler Word negInfWord{ 1020e05ab67SPeter Klausler Word{maxExponent}.SHIFTL(significandBits).IOR(Word::MASKL(1))}; 1030e05ab67SPeter Klausler if constexpr (kind == 10) { // x87 1040e05ab67SPeter Klausler infWord = infWord.IBSET(63); 1050e05ab67SPeter Klausler negInfWord = negInfWord.IBSET(63); 1060e05ab67SPeter Klausler } 1070e05ab67SPeter Klausler R inf{infWord}; 1080e05ab67SPeter Klausler R negInf{negInfWord}; 109ee5fa1f2SLuke Ireland TEST(!inf.IsNegative())(desc); 110ee5fa1f2SLuke Ireland TEST(!inf.IsNotANumber())(desc); 111ee5fa1f2SLuke Ireland TEST(inf.IsInfinite())(desc); 112ee5fa1f2SLuke Ireland TEST(!inf.IsZero())(desc); 113ee5fa1f2SLuke Ireland TEST(inf.RawBits().CompareUnsigned(inf.ABS().RawBits()) == Ordering::Equal) 114ee5fa1f2SLuke Ireland (desc); 115ee5fa1f2SLuke Ireland TEST(zero.Compare(inf) == Relation::Less)(desc); 116ee5fa1f2SLuke Ireland TEST(minusZero.Compare(inf) == Relation::Less)(desc); 117ee5fa1f2SLuke Ireland TEST(nan.Compare(inf) == Relation::Unordered)(desc); 118ee5fa1f2SLuke Ireland TEST(inf.Compare(inf) == Relation::Equal)(desc); 119ee5fa1f2SLuke Ireland TEST(negInf.IsNegative())(desc); 120ee5fa1f2SLuke Ireland TEST(!negInf.IsNotANumber())(desc); 121ee5fa1f2SLuke Ireland TEST(negInf.IsInfinite())(desc); 122ee5fa1f2SLuke Ireland TEST(!negInf.IsZero())(desc); 123ee5fa1f2SLuke Ireland TEST(inf.RawBits().CompareUnsigned(negInf.ABS().RawBits()) == Ordering::Equal) 124ee5fa1f2SLuke Ireland (desc); 125ee5fa1f2SLuke Ireland TEST(inf.RawBits().CompareUnsigned(negInf.Negate().RawBits()) == 126ee5fa1f2SLuke Ireland Ordering::Equal) 127ee5fa1f2SLuke Ireland (desc); 128ee5fa1f2SLuke Ireland TEST(inf.Negate().RawBits().CompareUnsigned(negInf.RawBits()) == 129ee5fa1f2SLuke Ireland Ordering::Equal) 130ee5fa1f2SLuke Ireland (desc); 131ee5fa1f2SLuke Ireland TEST(zero.Compare(negInf) == Relation::Greater)(desc); 132ee5fa1f2SLuke Ireland TEST(minusZero.Compare(negInf) == Relation::Greater)(desc); 133ee5fa1f2SLuke Ireland TEST(nan.Compare(negInf) == Relation::Unordered)(desc); 134ee5fa1f2SLuke Ireland TEST(inf.Compare(negInf) == Relation::Greater)(desc); 135ee5fa1f2SLuke Ireland TEST(negInf.Compare(negInf) == Relation::Equal)(desc); 136ee5fa1f2SLuke Ireland for (std::uint64_t j{0}; j < 63; ++j) { 137ee5fa1f2SLuke Ireland char ldesc[128]; 138ee5fa1f2SLuke Ireland std::uint64_t x{1}; 139ee5fa1f2SLuke Ireland x <<= j; 140ee5fa1f2SLuke Ireland std::snprintf(ldesc, sizeof ldesc, "%s j=%d x=0x%jx rm=%d", desc, 141ee5fa1f2SLuke Ireland static_cast<int>(j), static_cast<std::intmax_t>(x), rm); 142ee5fa1f2SLuke Ireland Integer8 ix{x}; 143ee5fa1f2SLuke Ireland TEST(!ix.IsNegative())(ldesc); 144ee5fa1f2SLuke Ireland MATCH(x, ix.ToUInt64())(ldesc); 145*fc97d2e6SPeter Klausler vr = R::FromInteger(ix, false, rounding); 146ee5fa1f2SLuke Ireland TEST(!vr.value.IsNegative())(ldesc); 147ee5fa1f2SLuke Ireland TEST(!vr.value.IsNotANumber())(ldesc); 148ee5fa1f2SLuke Ireland TEST(!vr.value.IsZero())(ldesc); 149ee5fa1f2SLuke Ireland auto ivf = vr.value.template ToInteger<Integer8>(); 150ee5fa1f2SLuke Ireland if (j > (maxExponent / 2)) { 151ee5fa1f2SLuke Ireland TEST(vr.flags.test(RealFlag::Overflow))(ldesc); 152ee5fa1f2SLuke Ireland TEST(vr.value.IsInfinite())(ldesc); 153ee5fa1f2SLuke Ireland TEST(ivf.flags.test(RealFlag::Overflow))(ldesc); 154ee5fa1f2SLuke Ireland MATCH(0x7fffffffffffffff, ivf.value.ToUInt64())(ldesc); 155ee5fa1f2SLuke Ireland } else { 156ee5fa1f2SLuke Ireland TEST(vr.flags.empty())(ldesc); 157ee5fa1f2SLuke Ireland TEST(!vr.value.IsInfinite())(ldesc); 158ee5fa1f2SLuke Ireland TEST(ivf.flags.empty())(ldesc); 159ee5fa1f2SLuke Ireland MATCH(x, ivf.value.ToUInt64())(ldesc); 160ee5fa1f2SLuke Ireland if (rounding.mode == RoundingMode::TiesToEven) { // to match stold() 161d5dd7d23SYoungsuk Kim std::string decimal; 162d5dd7d23SYoungsuk Kim llvm::raw_string_ostream ss{decimal}; 163ee5fa1f2SLuke Ireland vr.value.AsFortran(ss, kind, false /*exact*/); 164ee5fa1f2SLuke Ireland const char *p{decimal.data()}; 165ee5fa1f2SLuke Ireland MATCH(x, static_cast<std::uint64_t>(std::stold(decimal))) 166ee5fa1f2SLuke Ireland ("%s %s", ldesc, p); 167ee5fa1f2SLuke Ireland auto check{R::Read(p, rounding)}; 168ee5fa1f2SLuke Ireland auto icheck{check.value.template ToInteger<Integer8>()}; 169ee5fa1f2SLuke Ireland MATCH(x, icheck.value.ToUInt64())(ldesc); 170ee5fa1f2SLuke Ireland TEST(vr.value.Compare(check.value) == Relation::Equal)(ldesc); 171ee5fa1f2SLuke Ireland } 172ee5fa1f2SLuke Ireland } 173ee5fa1f2SLuke Ireland TEST(vr.value.ToWholeNumber().value.Compare(vr.value) == Relation::Equal) 174ee5fa1f2SLuke Ireland (ldesc); 175ee5fa1f2SLuke Ireland ix = ix.Negate().value; 176ee5fa1f2SLuke Ireland TEST(ix.IsNegative())(ldesc); 177ee5fa1f2SLuke Ireland x = -x; 178ee5fa1f2SLuke Ireland std::int64_t nx = x; 179ee5fa1f2SLuke Ireland MATCH(x, ix.ToUInt64())(ldesc); 180ee5fa1f2SLuke Ireland MATCH(nx, ix.ToInt64())(ldesc); 181ee5fa1f2SLuke Ireland vr = R::FromInteger(ix); 182ee5fa1f2SLuke Ireland TEST(vr.value.IsNegative())(ldesc); 183ee5fa1f2SLuke Ireland TEST(!vr.value.IsNotANumber())(ldesc); 184ee5fa1f2SLuke Ireland TEST(!vr.value.IsZero())(ldesc); 185ee5fa1f2SLuke Ireland ivf = vr.value.template ToInteger<Integer8>(); 186ee5fa1f2SLuke Ireland if (j > (maxExponent / 2)) { 187ee5fa1f2SLuke Ireland TEST(vr.flags.test(RealFlag::Overflow))(ldesc); 188ee5fa1f2SLuke Ireland TEST(vr.value.IsInfinite())(ldesc); 189ee5fa1f2SLuke Ireland TEST(ivf.flags.test(RealFlag::Overflow))(ldesc); 190ee5fa1f2SLuke Ireland MATCH(0x8000000000000000, ivf.value.ToUInt64())(ldesc); 191ee5fa1f2SLuke Ireland } else { 192ee5fa1f2SLuke Ireland TEST(vr.flags.empty())(ldesc); 193ee5fa1f2SLuke Ireland TEST(!vr.value.IsInfinite())(ldesc); 194ee5fa1f2SLuke Ireland TEST(ivf.flags.empty())(ldesc); 195ee5fa1f2SLuke Ireland MATCH(x, ivf.value.ToUInt64())(ldesc); 196ee5fa1f2SLuke Ireland MATCH(nx, ivf.value.ToInt64())(ldesc); 197ee5fa1f2SLuke Ireland } 198ee5fa1f2SLuke Ireland TEST(vr.value.ToWholeNumber().value.Compare(vr.value) == Relation::Equal) 199ee5fa1f2SLuke Ireland (ldesc); 200ee5fa1f2SLuke Ireland } 201ee5fa1f2SLuke Ireland } 202ee5fa1f2SLuke Ireland 203ee5fa1f2SLuke Ireland // Takes an integer and distributes its bits across a floating 204ee5fa1f2SLuke Ireland // point value. The LSB is used to complement the result. 205ee5fa1f2SLuke Ireland std::uint32_t MakeReal(std::uint32_t n) { 206ee5fa1f2SLuke Ireland int shifts[] = {-1, 31, 23, 30, 22, 0, 24, 29, 25, 28, 26, 1, 16, 21, 2, -1}; 207ee5fa1f2SLuke Ireland std::uint32_t x{0}; 208ee5fa1f2SLuke Ireland for (int j{1}; shifts[j] >= 0; ++j) { 209ee5fa1f2SLuke Ireland x |= ((n >> j) & 1) << shifts[j]; 210ee5fa1f2SLuke Ireland } 211ee5fa1f2SLuke Ireland x ^= -(n & 1); 212ee5fa1f2SLuke Ireland return x; 213ee5fa1f2SLuke Ireland } 214ee5fa1f2SLuke Ireland 215ee5fa1f2SLuke Ireland std::uint64_t MakeReal(std::uint64_t n) { 216ee5fa1f2SLuke Ireland int shifts[] = { 217ee5fa1f2SLuke Ireland -1, 63, 52, 62, 51, 0, 53, 61, 54, 60, 55, 59, 1, 16, 50, 2, -1}; 218ee5fa1f2SLuke Ireland std::uint64_t x{0}; 219ee5fa1f2SLuke Ireland for (int j{1}; shifts[j] >= 0; ++j) { 220ee5fa1f2SLuke Ireland x |= ((n >> j) & 1) << shifts[j]; 221ee5fa1f2SLuke Ireland } 222ee5fa1f2SLuke Ireland x ^= -(n & 1); 223ee5fa1f2SLuke Ireland return x; 224ee5fa1f2SLuke Ireland } 225ee5fa1f2SLuke Ireland 226ee5fa1f2SLuke Ireland inline bool IsNaN(std::uint32_t x) { 227ee5fa1f2SLuke Ireland return (x & 0x7f800000) == 0x7f800000 && (x & 0x007fffff) != 0; 228ee5fa1f2SLuke Ireland } 229ee5fa1f2SLuke Ireland 230ee5fa1f2SLuke Ireland inline bool IsNaN(std::uint64_t x) { 231ee5fa1f2SLuke Ireland return (x & 0x7ff0000000000000) == 0x7ff0000000000000 && 232ee5fa1f2SLuke Ireland (x & 0x000fffffffffffff) != 0; 233ee5fa1f2SLuke Ireland } 234ee5fa1f2SLuke Ireland 235ee5fa1f2SLuke Ireland inline bool IsInfinite(std::uint32_t x) { 236ee5fa1f2SLuke Ireland return (x & 0x7fffffff) == 0x7f800000; 237ee5fa1f2SLuke Ireland } 238ee5fa1f2SLuke Ireland 239ee5fa1f2SLuke Ireland inline bool IsInfinite(std::uint64_t x) { 240ee5fa1f2SLuke Ireland return (x & 0x7fffffffffffffff) == 0x7ff0000000000000; 241ee5fa1f2SLuke Ireland } 242ee5fa1f2SLuke Ireland 243ee5fa1f2SLuke Ireland inline bool IsNegative(std::uint32_t x) { return (x & 0x80000000) != 0; } 244ee5fa1f2SLuke Ireland 245ee5fa1f2SLuke Ireland inline bool IsNegative(std::uint64_t x) { 246ee5fa1f2SLuke Ireland return (x & 0x8000000000000000) != 0; 247ee5fa1f2SLuke Ireland } 248ee5fa1f2SLuke Ireland 249ee5fa1f2SLuke Ireland inline std::uint32_t NormalizeNaN(std::uint32_t x) { 250ee5fa1f2SLuke Ireland if (IsNaN(x)) { 251ee5fa1f2SLuke Ireland x = 0x7fe00000; 252ee5fa1f2SLuke Ireland } 253ee5fa1f2SLuke Ireland return x; 254ee5fa1f2SLuke Ireland } 255ee5fa1f2SLuke Ireland 256ee5fa1f2SLuke Ireland inline std::uint64_t NormalizeNaN(std::uint64_t x) { 257ee5fa1f2SLuke Ireland if (IsNaN(x)) { 258ee5fa1f2SLuke Ireland x = 0x7ffc000000000000; 259ee5fa1f2SLuke Ireland } 260ee5fa1f2SLuke Ireland return x; 261ee5fa1f2SLuke Ireland } 262ee5fa1f2SLuke Ireland 263ee5fa1f2SLuke Ireland enum FlagBits { 264ee5fa1f2SLuke Ireland Overflow = 1, 265ee5fa1f2SLuke Ireland DivideByZero = 2, 266ee5fa1f2SLuke Ireland InvalidArgument = 4, 267ee5fa1f2SLuke Ireland Underflow = 8, 268ee5fa1f2SLuke Ireland Inexact = 16, 269ee5fa1f2SLuke Ireland }; 270ee5fa1f2SLuke Ireland 271ee5fa1f2SLuke Ireland #ifdef __clang__ 272ee5fa1f2SLuke Ireland // clang support for fenv.h is broken, so tests of flag settings 273ee5fa1f2SLuke Ireland // are disabled. 274ee5fa1f2SLuke Ireland inline std::uint32_t FlagsToBits(const RealFlags &) { return 0; } 275ee5fa1f2SLuke Ireland #else 276ee5fa1f2SLuke Ireland inline std::uint32_t FlagsToBits(const RealFlags &flags) { 277ee5fa1f2SLuke Ireland std::uint32_t bits{0}; 278ee5fa1f2SLuke Ireland if (flags.test(RealFlag::Overflow)) { 279ee5fa1f2SLuke Ireland bits |= Overflow; 280ee5fa1f2SLuke Ireland } 281ee5fa1f2SLuke Ireland if (flags.test(RealFlag::DivideByZero)) { 282ee5fa1f2SLuke Ireland bits |= DivideByZero; 283ee5fa1f2SLuke Ireland } 284ee5fa1f2SLuke Ireland if (flags.test(RealFlag::InvalidArgument)) { 285ee5fa1f2SLuke Ireland bits |= InvalidArgument; 286ee5fa1f2SLuke Ireland } 287ee5fa1f2SLuke Ireland if (flags.test(RealFlag::Underflow)) { 288ee5fa1f2SLuke Ireland bits |= Underflow; 289ee5fa1f2SLuke Ireland } 290ee5fa1f2SLuke Ireland if (flags.test(RealFlag::Inexact)) { 291ee5fa1f2SLuke Ireland bits |= Inexact; 292ee5fa1f2SLuke Ireland } 293ee5fa1f2SLuke Ireland return bits; 294ee5fa1f2SLuke Ireland } 295ee5fa1f2SLuke Ireland #endif // __clang__ 296ee5fa1f2SLuke Ireland 297ee5fa1f2SLuke Ireland template <typename UINT = std::uint32_t, typename FLT = float, typename REAL> 298ee5fa1f2SLuke Ireland void inttest(std::int64_t x, int pass, Rounding rounding) { 299ee5fa1f2SLuke Ireland union { 300ee5fa1f2SLuke Ireland UINT ui; 301ee5fa1f2SLuke Ireland FLT f; 302ee5fa1f2SLuke Ireland } u; 303ee5fa1f2SLuke Ireland ScopedHostFloatingPointEnvironment fpenv; 304ee5fa1f2SLuke Ireland Integer8 ix{x}; 305ee5fa1f2SLuke Ireland ValueWithRealFlags<REAL> real; 306*fc97d2e6SPeter Klausler real = real.value.FromInteger(ix, false, rounding); 307ee5fa1f2SLuke Ireland #ifndef __clang__ // broken and also slow 308ee5fa1f2SLuke Ireland fpenv.ClearFlags(); 309ee5fa1f2SLuke Ireland #endif 310ee5fa1f2SLuke Ireland FLT fcheck = x; // TODO unsigned too 311ee5fa1f2SLuke Ireland auto actualFlags{FlagsToBits(fpenv.CurrentFlags())}; 312ee5fa1f2SLuke Ireland u.f = fcheck; 313ee5fa1f2SLuke Ireland UINT rcheck{NormalizeNaN(u.ui)}; 314ee5fa1f2SLuke Ireland UINT check = real.value.RawBits().ToUInt64(); 315ee5fa1f2SLuke Ireland MATCH(rcheck, check)("%d 0x%llx", pass, x); 316ee5fa1f2SLuke Ireland MATCH(actualFlags, FlagsToBits(real.flags))("%d 0x%llx", pass, x); 317ee5fa1f2SLuke Ireland } 318ee5fa1f2SLuke Ireland 319ee5fa1f2SLuke Ireland template <typename FLT = float> FLT ToIntPower(FLT x, int power) { 320ee5fa1f2SLuke Ireland if (power == 0) { 321ee5fa1f2SLuke Ireland return x / x; 322ee5fa1f2SLuke Ireland } 323ee5fa1f2SLuke Ireland bool negative{power < 0}; 324ee5fa1f2SLuke Ireland if (negative) { 325ee5fa1f2SLuke Ireland power = -power; 326ee5fa1f2SLuke Ireland } 327ee5fa1f2SLuke Ireland FLT result{1}; 328ee5fa1f2SLuke Ireland while (power > 0) { 329ee5fa1f2SLuke Ireland if (power & 1) { 330ee5fa1f2SLuke Ireland result *= x; 331ee5fa1f2SLuke Ireland } 332ee5fa1f2SLuke Ireland x *= x; 333ee5fa1f2SLuke Ireland power >>= 1; 334ee5fa1f2SLuke Ireland } 335ee5fa1f2SLuke Ireland if (negative) { 336ee5fa1f2SLuke Ireland result = 1.0 / result; 337ee5fa1f2SLuke Ireland } 338ee5fa1f2SLuke Ireland return result; 339ee5fa1f2SLuke Ireland } 340ee5fa1f2SLuke Ireland 341ee5fa1f2SLuke Ireland template <typename FLT, int decimalDigits> 342ee5fa1f2SLuke Ireland FLT TimesIntPowerOfTen(FLT x, int power) { 343ee5fa1f2SLuke Ireland if (power > decimalDigits || power < -decimalDigits) { 344ee5fa1f2SLuke Ireland auto maxExactPowerOfTen{ 345ee5fa1f2SLuke Ireland TimesIntPowerOfTen<FLT, decimalDigits>(1, decimalDigits)}; 346ee5fa1f2SLuke Ireland auto big{ToIntPower<FLT>(maxExactPowerOfTen, power / decimalDigits)}; 347ee5fa1f2SLuke Ireland auto small{ 348ee5fa1f2SLuke Ireland TimesIntPowerOfTen<FLT, decimalDigits>(1, power % decimalDigits)}; 349ee5fa1f2SLuke Ireland return (x * big) * small; 350ee5fa1f2SLuke Ireland } 351ee5fa1f2SLuke Ireland return x * ToIntPower<FLT>(10.0, power); 352ee5fa1f2SLuke Ireland } 353ee5fa1f2SLuke Ireland 354ee5fa1f2SLuke Ireland template <typename UINT = std::uint32_t, typename FLT = float, 355ee5fa1f2SLuke Ireland typename REAL = Real4> 356ee5fa1f2SLuke Ireland void subsetTests(int pass, Rounding rounding, std::uint32_t opds) { 357ee5fa1f2SLuke Ireland for (int j{0}; j < 63; ++j) { 358ee5fa1f2SLuke Ireland std::int64_t x{1}; 359ee5fa1f2SLuke Ireland x <<= j; 360ee5fa1f2SLuke Ireland inttest<UINT, FLT, REAL>(x, pass, rounding); 361ee5fa1f2SLuke Ireland inttest<UINT, FLT, REAL>(-x, pass, rounding); 362ee5fa1f2SLuke Ireland } 363ee5fa1f2SLuke Ireland inttest<UINT, FLT, REAL>(0, pass, rounding); 364ee5fa1f2SLuke Ireland inttest<UINT, FLT, REAL>( 365ee5fa1f2SLuke Ireland static_cast<std::int64_t>(0x8000000000000000), pass, rounding); 366ee5fa1f2SLuke Ireland 367ee5fa1f2SLuke Ireland union { 368ee5fa1f2SLuke Ireland UINT ui; 369ee5fa1f2SLuke Ireland FLT f; 370ee5fa1f2SLuke Ireland } u; 371ee5fa1f2SLuke Ireland ScopedHostFloatingPointEnvironment fpenv; 372ee5fa1f2SLuke Ireland 373ee5fa1f2SLuke Ireland for (UINT j{0}; j < opds; ++j) { 374ee5fa1f2SLuke Ireland 375ee5fa1f2SLuke Ireland UINT rj{MakeReal(j)}; 376ee5fa1f2SLuke Ireland u.ui = rj; 377ee5fa1f2SLuke Ireland FLT fj{u.f}; 378ee5fa1f2SLuke Ireland REAL x{typename REAL::Word{std::uint64_t{rj}}}; 379ee5fa1f2SLuke Ireland 380ee5fa1f2SLuke Ireland // unary operations 381ee5fa1f2SLuke Ireland { 382ee5fa1f2SLuke Ireland ValueWithRealFlags<REAL> aint{x.ToWholeNumber()}; 383ee5fa1f2SLuke Ireland #ifndef __clang__ // broken and also slow 384ee5fa1f2SLuke Ireland fpenv.ClearFlags(); 385ee5fa1f2SLuke Ireland #endif 386ee5fa1f2SLuke Ireland FLT fcheck{std::trunc(fj)}; 387ee5fa1f2SLuke Ireland auto actualFlags{FlagsToBits(fpenv.CurrentFlags())}; 388ee5fa1f2SLuke Ireland actualFlags &= ~Inexact; // x86 std::trunc can set Inexact; AINT ain't 389ee5fa1f2SLuke Ireland u.f = fcheck; 390ee5fa1f2SLuke Ireland #ifndef __clang__ 391ee5fa1f2SLuke Ireland if (IsNaN(u.ui)) { 392ee5fa1f2SLuke Ireland actualFlags |= InvalidArgument; // x86 std::trunc(NaN) workaround 393ee5fa1f2SLuke Ireland } 394ee5fa1f2SLuke Ireland #endif 395ee5fa1f2SLuke Ireland UINT rcheck{NormalizeNaN(u.ui)}; 396ee5fa1f2SLuke Ireland UINT check = aint.value.RawBits().ToUInt64(); 397ee5fa1f2SLuke Ireland MATCH(rcheck, check) 398ee5fa1f2SLuke Ireland ("%d AINT(0x%jx)", pass, static_cast<std::intmax_t>(rj)); 399ee5fa1f2SLuke Ireland MATCH(actualFlags, FlagsToBits(aint.flags)) 400ee5fa1f2SLuke Ireland ("%d AINT(0x%jx)", pass, static_cast<std::intmax_t>(rj)); 401ee5fa1f2SLuke Ireland } 402ee5fa1f2SLuke Ireland 403ee5fa1f2SLuke Ireland { 4041ef5e6deSPeter Klausler ValueWithRealFlags<REAL> root{x.SQRT(rounding)}; 4051ef5e6deSPeter Klausler #ifndef __clang__ // broken and also slow 4061ef5e6deSPeter Klausler fpenv.ClearFlags(); 4071ef5e6deSPeter Klausler #endif 4081ef5e6deSPeter Klausler FLT fcheck{std::sqrt(fj)}; 4091ef5e6deSPeter Klausler auto actualFlags{FlagsToBits(fpenv.CurrentFlags())}; 4101ef5e6deSPeter Klausler u.f = fcheck; 4111ef5e6deSPeter Klausler UINT rcheck{NormalizeNaN(u.ui)}; 4121ef5e6deSPeter Klausler UINT check = root.value.RawBits().ToUInt64(); 4131ef5e6deSPeter Klausler MATCH(rcheck, check) 4141ef5e6deSPeter Klausler ("%d SQRT(0x%jx)", pass, static_cast<std::intmax_t>(rj)); 4151ef5e6deSPeter Klausler MATCH(actualFlags, FlagsToBits(root.flags)) 4161ef5e6deSPeter Klausler ("%d SQRT(0x%jx)", pass, static_cast<std::intmax_t>(rj)); 4171ef5e6deSPeter Klausler } 4181ef5e6deSPeter Klausler 4191ef5e6deSPeter Klausler { 420ee5fa1f2SLuke Ireland MATCH(IsNaN(rj), x.IsNotANumber()) 421ee5fa1f2SLuke Ireland ("%d IsNaN(0x%jx)", pass, static_cast<std::intmax_t>(rj)); 422ee5fa1f2SLuke Ireland MATCH(IsInfinite(rj), x.IsInfinite()) 423ee5fa1f2SLuke Ireland ("%d IsInfinite(0x%jx)", pass, static_cast<std::intmax_t>(rj)); 424ee5fa1f2SLuke Ireland 425ee5fa1f2SLuke Ireland static constexpr int kind{REAL::bits / 8}; 426d5dd7d23SYoungsuk Kim std::string s, cssBuf; 427d5dd7d23SYoungsuk Kim llvm::raw_string_ostream ss{s}; 4288670e499SCaroline Concatto llvm::raw_string_ostream css{cssBuf}; 429ee5fa1f2SLuke Ireland x.AsFortran(ss, kind, false /*exact*/); 430ee5fa1f2SLuke Ireland if (IsNaN(rj)) { 431ee5fa1f2SLuke Ireland css << "(0._" << kind << "/0.)"; 432d5dd7d23SYoungsuk Kim MATCH(cssBuf, s) 433ee5fa1f2SLuke Ireland ("%d invalid(0x%jx)", pass, static_cast<std::intmax_t>(rj)); 434ee5fa1f2SLuke Ireland } else if (IsInfinite(rj)) { 435ee5fa1f2SLuke Ireland css << '('; 436ee5fa1f2SLuke Ireland if (IsNegative(rj)) { 437ee5fa1f2SLuke Ireland css << '-'; 438ee5fa1f2SLuke Ireland } 439ee5fa1f2SLuke Ireland css << "1._" << kind << "/0.)"; 440d5dd7d23SYoungsuk Kim MATCH(cssBuf, s) 441ee5fa1f2SLuke Ireland ("%d overflow(0x%jx)", pass, static_cast<std::intmax_t>(rj)); 442ee5fa1f2SLuke Ireland } else { 443ee5fa1f2SLuke Ireland const char *p = s.data(); 444ee5fa1f2SLuke Ireland if (*p == '(') { 445ee5fa1f2SLuke Ireland ++p; 446ee5fa1f2SLuke Ireland } 447ee5fa1f2SLuke Ireland auto readBack{REAL::Read(p, rounding)}; 448ee5fa1f2SLuke Ireland MATCH(rj, readBack.value.RawBits().ToUInt64()) 449ee5fa1f2SLuke Ireland ("%d Read(AsFortran()) 0x%jx %s %g", pass, 450ee5fa1f2SLuke Ireland static_cast<std::intmax_t>(rj), s.data(), static_cast<double>(fj)); 451ee5fa1f2SLuke Ireland MATCH('_', *p) 452ee5fa1f2SLuke Ireland ("%d Read(AsFortran()) 0x%jx %s %d", pass, 453ee5fa1f2SLuke Ireland static_cast<std::intmax_t>(rj), s.data(), 454ee5fa1f2SLuke Ireland static_cast<int>(p - s.data())); 455ee5fa1f2SLuke Ireland } 456ee5fa1f2SLuke Ireland } 457ee5fa1f2SLuke Ireland 458ee5fa1f2SLuke Ireland // dyadic operations 459ee5fa1f2SLuke Ireland for (UINT k{0}; k < opds; ++k) { 460ee5fa1f2SLuke Ireland UINT rk{MakeReal(k)}; 461ee5fa1f2SLuke Ireland u.ui = rk; 462ee5fa1f2SLuke Ireland FLT fk{u.f}; 463ee5fa1f2SLuke Ireland REAL y{typename REAL::Word{std::uint64_t{rk}}}; 464ee5fa1f2SLuke Ireland { 465ee5fa1f2SLuke Ireland ValueWithRealFlags<REAL> sum{x.Add(y, rounding)}; 466ee5fa1f2SLuke Ireland #ifndef __clang__ // broken and also slow 467ee5fa1f2SLuke Ireland fpenv.ClearFlags(); 468ee5fa1f2SLuke Ireland #endif 469ee5fa1f2SLuke Ireland FLT fcheck{fj + fk}; 470ee5fa1f2SLuke Ireland auto actualFlags{FlagsToBits(fpenv.CurrentFlags())}; 471ee5fa1f2SLuke Ireland u.f = fcheck; 472ee5fa1f2SLuke Ireland UINT rcheck{NormalizeNaN(u.ui)}; 473ee5fa1f2SLuke Ireland UINT check = sum.value.RawBits().ToUInt64(); 474ee5fa1f2SLuke Ireland MATCH(rcheck, check) 475ee5fa1f2SLuke Ireland ("%d 0x%jx + 0x%jx", pass, static_cast<std::intmax_t>(rj), 476ee5fa1f2SLuke Ireland static_cast<std::intmax_t>(rk)); 477ee5fa1f2SLuke Ireland MATCH(actualFlags, FlagsToBits(sum.flags)) 478ee5fa1f2SLuke Ireland ("%d 0x%jx + 0x%jx", pass, static_cast<std::intmax_t>(rj), 479ee5fa1f2SLuke Ireland static_cast<std::intmax_t>(rk)); 480ee5fa1f2SLuke Ireland } 481ee5fa1f2SLuke Ireland { 482ee5fa1f2SLuke Ireland ValueWithRealFlags<REAL> diff{x.Subtract(y, rounding)}; 483ee5fa1f2SLuke Ireland #ifndef __clang__ // broken and also slow 484ee5fa1f2SLuke Ireland fpenv.ClearFlags(); 485ee5fa1f2SLuke Ireland #endif 486ee5fa1f2SLuke Ireland FLT fcheck{fj - fk}; 487ee5fa1f2SLuke Ireland auto actualFlags{FlagsToBits(fpenv.CurrentFlags())}; 488ee5fa1f2SLuke Ireland u.f = fcheck; 489ee5fa1f2SLuke Ireland UINT rcheck{NormalizeNaN(u.ui)}; 490ee5fa1f2SLuke Ireland UINT check = diff.value.RawBits().ToUInt64(); 491ee5fa1f2SLuke Ireland MATCH(rcheck, check) 492ee5fa1f2SLuke Ireland ("%d 0x%jx - 0x%jx", pass, static_cast<std::intmax_t>(rj), 493ee5fa1f2SLuke Ireland static_cast<std::intmax_t>(rk)); 494ee5fa1f2SLuke Ireland MATCH(actualFlags, FlagsToBits(diff.flags)) 495ee5fa1f2SLuke Ireland ("%d 0x%jx - 0x%jx", pass, static_cast<std::intmax_t>(rj), 496ee5fa1f2SLuke Ireland static_cast<std::intmax_t>(rk)); 497ee5fa1f2SLuke Ireland } 498ee5fa1f2SLuke Ireland { 499ee5fa1f2SLuke Ireland ValueWithRealFlags<REAL> prod{x.Multiply(y, rounding)}; 500ee5fa1f2SLuke Ireland #ifndef __clang__ // broken and also slow 501ee5fa1f2SLuke Ireland fpenv.ClearFlags(); 502ee5fa1f2SLuke Ireland #endif 503ee5fa1f2SLuke Ireland FLT fcheck{fj * fk}; 504ee5fa1f2SLuke Ireland auto actualFlags{FlagsToBits(fpenv.CurrentFlags())}; 505ee5fa1f2SLuke Ireland u.f = fcheck; 506ee5fa1f2SLuke Ireland UINT rcheck{NormalizeNaN(u.ui)}; 507ee5fa1f2SLuke Ireland UINT check = prod.value.RawBits().ToUInt64(); 508ee5fa1f2SLuke Ireland MATCH(rcheck, check) 509ee5fa1f2SLuke Ireland ("%d 0x%jx * 0x%jx", pass, static_cast<std::intmax_t>(rj), 510ee5fa1f2SLuke Ireland static_cast<std::intmax_t>(rk)); 511ee5fa1f2SLuke Ireland MATCH(actualFlags, FlagsToBits(prod.flags)) 512ee5fa1f2SLuke Ireland ("%d 0x%jx * 0x%jx", pass, static_cast<std::intmax_t>(rj), 513ee5fa1f2SLuke Ireland static_cast<std::intmax_t>(rk)); 514ee5fa1f2SLuke Ireland } 515ee5fa1f2SLuke Ireland { 516ee5fa1f2SLuke Ireland ValueWithRealFlags<REAL> quot{x.Divide(y, rounding)}; 517ee5fa1f2SLuke Ireland #ifndef __clang__ // broken and also slow 518ee5fa1f2SLuke Ireland fpenv.ClearFlags(); 519ee5fa1f2SLuke Ireland #endif 520ee5fa1f2SLuke Ireland FLT fcheck{fj / fk}; 521ee5fa1f2SLuke Ireland auto actualFlags{FlagsToBits(fpenv.CurrentFlags())}; 522ee5fa1f2SLuke Ireland u.f = fcheck; 523ee5fa1f2SLuke Ireland UINT rcheck{NormalizeNaN(u.ui)}; 524ee5fa1f2SLuke Ireland UINT check = quot.value.RawBits().ToUInt64(); 525ee5fa1f2SLuke Ireland MATCH(rcheck, check) 526ee5fa1f2SLuke Ireland ("%d 0x%jx / 0x%jx", pass, static_cast<std::intmax_t>(rj), 527ee5fa1f2SLuke Ireland static_cast<std::intmax_t>(rk)); 528ee5fa1f2SLuke Ireland MATCH(actualFlags, FlagsToBits(quot.flags)) 529ee5fa1f2SLuke Ireland ("%d 0x%jx / 0x%jx", pass, static_cast<std::intmax_t>(rj), 530ee5fa1f2SLuke Ireland static_cast<std::intmax_t>(rk)); 531ee5fa1f2SLuke Ireland } 532ee5fa1f2SLuke Ireland } 533ee5fa1f2SLuke Ireland } 534ee5fa1f2SLuke Ireland } 535ee5fa1f2SLuke Ireland 536ee5fa1f2SLuke Ireland void roundTest(int rm, Rounding rounding, std::uint32_t opds) { 537ee5fa1f2SLuke Ireland basicTests<Real2>(rm, rounding); 538ee5fa1f2SLuke Ireland basicTests<Real3>(rm, rounding); 539ee5fa1f2SLuke Ireland basicTests<Real4>(rm, rounding); 540ee5fa1f2SLuke Ireland basicTests<Real8>(rm, rounding); 54158b51492Smadanial0 #ifdef __x86_64__ 542ee5fa1f2SLuke Ireland basicTests<Real10>(rm, rounding); 54358b51492Smadanial0 #endif 544ee5fa1f2SLuke Ireland basicTests<Real16>(rm, rounding); 545ee5fa1f2SLuke Ireland ScopedHostFloatingPointEnvironment::SetRounding(rounding); 546ee5fa1f2SLuke Ireland subsetTests<std::uint32_t, float, Real4>(rm, rounding, opds); 547ee5fa1f2SLuke Ireland subsetTests<std::uint64_t, double, Real8>(rm, rounding, opds); 548ee5fa1f2SLuke Ireland } 549ee5fa1f2SLuke Ireland 550ee5fa1f2SLuke Ireland int main() { 551ee5fa1f2SLuke Ireland dumpTest(); 552ee5fa1f2SLuke Ireland std::uint32_t opds{512}; // for quick testing by default 553ee5fa1f2SLuke Ireland if (const char *p{std::getenv("REAL_TEST_OPERANDS")}) { 554ee5fa1f2SLuke Ireland // Use 8192 or 16384 for more exhaustive testing. 555ee5fa1f2SLuke Ireland opds = std::atol(p); 556ee5fa1f2SLuke Ireland } 557ee5fa1f2SLuke Ireland roundTest(0, Rounding{RoundingMode::TiesToEven}, opds); 558ee5fa1f2SLuke Ireland roundTest(1, Rounding{RoundingMode::ToZero}, opds); 559ee5fa1f2SLuke Ireland roundTest(2, Rounding{RoundingMode::Up}, opds); 560ee5fa1f2SLuke Ireland roundTest(3, Rounding{RoundingMode::Down}, opds); 561ee5fa1f2SLuke Ireland // TODO: how to test Rounding::TiesAwayFromZero on x86? 562ee5fa1f2SLuke Ireland return testing::Complete(); 563ee5fa1f2SLuke Ireland } 564