xref: /llvm-project/flang/unittests/Decimal/thorough-test.cpp (revision ee5fa1f2338abb2dace0c43116cd73c283f96a3b)
1 #include "flang/Decimal/decimal.h"
2 #include <cinttypes>
3 #include <cstdio>
4 #include <cstring>
5 #include <iostream>
6 
7 static constexpr int incr{1};  // steps through all values
8 static constexpr bool doNegative{true};
9 static constexpr bool doMinimize{true};
10 
11 using namespace Fortran::decimal;
12 
13 static std::uint64_t tests{0};
14 static std::uint64_t fails{0};
15 
16 union u {
17   float x;
18   std::uint32_t u;
19 };
20 
21 std::ostream &failed(float x) {
22   ++fails;
23   union u u;
24   u.x = x;
25   return std::cout << "FAIL: 0x" << std::hex << u.u << std::dec;
26 }
27 
28 void testReadback(float x, int flags) {
29   char buffer[1024];
30   union u u;
31   u.x = x;
32   if (!(tests & 0x3fffff)) {
33     std::cerr << "\n0x" << std::hex << u.u << std::dec << ' ';
34   } else if (!(tests & 0xffff)) {
35     std::cerr << '.';
36   }
37   ++tests;
38   auto result{ConvertFloatToDecimal(buffer, sizeof buffer,
39       static_cast<enum DecimalConversionFlags>(flags), 1024, RoundNearest, x)};
40   if (result.str == nullptr) {
41     failed(x) << ' ' << flags << ": no result str\n";
42   } else {
43     float y{0};
44     char *q{const_cast<char *>(result.str)};
45     if ((*q >= '0' && *q <= '9') ||
46         ((*q == '-' || *q == '+') && q[1] >= '0' && q[1] <= '9')) {
47       int expo{result.decimalExponent};
48       expo -= result.length;
49       if (*q == '-' || *q == '+') {
50         ++expo;
51       }
52       std::sprintf(q + result.length, "e%d", expo);
53     }
54     const char *p{q};
55     auto rflags{ConvertDecimalToFloat(&p, &y, RoundNearest)};
56     if (!(x == x)) {
57       if (y == y || *p != '\0' || (rflags & Invalid)) {
58         u.x = y;
59         failed(x) << " (NaN) " << flags << ": -> '" << result.str << "' -> 0x"
60                   << std::hex << u.u << std::dec << " '" << p << "' " << rflags
61                   << '\n';
62       }
63     } else if (x != y || *p != '\0' || (rflags & Invalid)) {
64       u.x = y;
65       failed(x) << ' ' << flags << ": -> '" << result.str << "' -> 0x"
66                 << std::hex << u.u << std::dec << " '" << p << "' " << rflags
67                 << '\n';
68     }
69   }
70 }
71 
72 int main() {
73   union u u;
74   for (u.u = 0; u.u < 0x7f800010; u.u += incr) {
75     testReadback(u.x, 0);
76     if constexpr (doNegative) {
77       testReadback(-u.x, 0);
78     }
79     if constexpr (doMinimize) {
80       testReadback(u.x, Minimize);
81       if constexpr (doNegative) {
82         testReadback(-u.x, Minimize);
83       }
84     }
85   }
86   std::cout << '\n' << tests << " tests run, " << fails << " tests failed\n";
87   return fails > 0;
88 }
89