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