xref: /llvm-project/flang/unittests/Decimal/quick-sanity-test.cpp (revision ecd691750648b72b9e0ce6879fcfa60396693a77)
1 #include "flang/Decimal/decimal.h"
2 #include "llvm/Support/raw_ostream.h"
3 #include <cinttypes>
4 #include <cstdio>
5 #include <cstring>
6 
7 using namespace Fortran::decimal;
8 
9 static int tests{0};
10 static int fails{0};
11 
12 union u {
13   float x;
14   std::uint32_t u;
15 };
16 
failed(float x)17 llvm::raw_ostream &failed(float x) {
18   ++fails;
19   union u u;
20   u.x = x;
21   llvm::outs() << "FAIL: 0x";
22   return llvm::outs().write_hex(u.u);
23 }
24 
testDirect(float x,const char * expect,int expectExpo,int flags=0)25 void testDirect(float x, const char *expect, int expectExpo, int flags = 0) {
26   char buffer[1024];
27   ++tests;
28   auto result{ConvertFloatToDecimal(buffer, sizeof buffer,
29       static_cast<enum DecimalConversionFlags>(flags), 1024, RoundNearest, x)};
30   if (result.str == nullptr) {
31     failed(x) << ' ' << flags << ": no result str\n";
32   } else if (std::strcmp(result.str, expect) != 0 ||
33       result.decimalExponent != expectExpo) {
34     failed(x) << ' ' << flags << ": expect '." << expect << 'e' << expectExpo
35               << "', got '." << result.str << 'e' << result.decimalExponent
36               << "'\n";
37   }
38 }
39 
testReadback(float x,int flags)40 void testReadback(float x, int flags) {
41   char buffer[1024];
42   ++tests;
43   auto result{ConvertFloatToDecimal(buffer, sizeof buffer,
44       static_cast<enum DecimalConversionFlags>(flags), 1024, RoundNearest, x)};
45   if (result.str == nullptr) {
46     failed(x) << ' ' << flags << ": no result str\n";
47   } else {
48     float y{0};
49     char *q{const_cast<char *>(result.str)};
50     int expo{result.decimalExponent};
51     expo -= result.length;
52     if (*q == '-' || *q == '+') {
53       ++expo;
54     }
55     if (q >= buffer && q < buffer + sizeof buffer) {
56       std::snprintf(q + result.length,
57           buffer + sizeof buffer - (q + result.length), "e%d", expo);
58     }
59     const char *p{q};
60     auto rflags{ConvertDecimalToFloat(&p, &y, RoundNearest)};
61     union u u;
62     if (!(x == x)) {
63       if (y == y || *p != '\0' || (rflags & Invalid)) {
64         u.x = y;
65         (failed(x) << " (NaN) " << flags << ": -> '" << result.str << "' -> 0x")
66                 .write_hex(u.u)
67             << " '" << p << "' " << rflags << '\n';
68       }
69     } else if (x != y || *p != '\0' || (rflags & Invalid)) {
70       u.x = x;
71       (failed(x) << ' ' << flags << ": -> '" << result.str << "' -> 0x")
72               .write_hex(u.u)
73           << " '" << p << "' " << rflags << '\n';
74     }
75   }
76 }
77 
main()78 int main() {
79   union u u;
80   testDirect(-1.0, "-1", 1);
81   testDirect(0.0, "0", 0);
82   testDirect(0.0, "+0", 0, AlwaysSign);
83   testDirect(1.0, "1", 1);
84   testDirect(2.0, "2", 1);
85   testDirect(-1.0, "-1", 1);
86   testDirect(314159, "314159", 6);
87   testDirect(0.0625, "625", -1);
88   u.u = 0x80000000;
89   testDirect(u.x, "-0", 0);
90   u.u = 0x7f800000;
91   testDirect(u.x, "Inf", 0);
92   testDirect(u.x, "+Inf", 0, AlwaysSign);
93   u.u = 0xff800000;
94   testDirect(u.x, "-Inf", 0);
95   u.u = 0xffffffff;
96   testDirect(u.x, "NaN", 0);
97   testDirect(u.x, "NaN", 0, AlwaysSign);
98   u.u = 1;
99   testDirect(u.x,
100       "140129846432481707092372958328991613128026194187651577175706828388979108"
101       "268586060148663818836212158203125",
102       -44, 0);
103   testDirect(u.x, "1", -44, Minimize);
104   u.u = 0x7f777777;
105   testDirect(u.x, "3289396118917826996438159226753253376", 39, 0);
106   testDirect(u.x, "32893961", 39, Minimize);
107   for (u.u = 0; u.u < 16; ++u.u) {
108     testReadback(u.x, 0);
109     testReadback(-u.x, 0);
110     testReadback(u.x, Minimize);
111     testReadback(-u.x, Minimize);
112   }
113   for (u.u = 1; u.u < 0x7f800000; u.u *= 2) {
114     testReadback(u.x, 0);
115     testReadback(-u.x, 0);
116     testReadback(u.x, Minimize);
117     testReadback(-u.x, Minimize);
118   }
119   for (u.u = 0x7f7ffff0; u.u < 0x7f800010; ++u.u) {
120     testReadback(u.x, 0);
121     testReadback(-u.x, 0);
122     testReadback(u.x, Minimize);
123     testReadback(-u.x, Minimize);
124   }
125   for (u.u = 0; u.u < 0x7f800000; u.u += 65536) {
126     testReadback(u.x, 0);
127     testReadback(-u.x, 0);
128     testReadback(u.x, Minimize);
129     testReadback(-u.x, Minimize);
130   }
131   for (u.u = 0; u.u < 0x7f800000; u.u += 99999) {
132     testReadback(u.x, 0);
133     testReadback(-u.x, 0);
134     testReadback(u.x, Minimize);
135     testReadback(-u.x, Minimize);
136   }
137   for (u.u = 0; u.u < 0x7f800000; u.u += 32767) {
138     testReadback(u.x, 0);
139     testReadback(-u.x, 0);
140     testReadback(u.x, Minimize);
141     testReadback(-u.x, Minimize);
142   }
143   llvm::outs() << tests << " tests run, " << fails << " tests failed\n";
144   return fails > 0;
145 }
146