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