Line data Source code
1 : /******************************************************************************
2 : * $Id$
3 : *
4 : * Project: GDAL Core
5 : * Purpose: Test GFloat16.
6 : * Author: Erik Schnetter <eschnetter at perimeterinstitute.ca>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_float.h"
15 :
16 : #include "gtest_include.h"
17 :
18 : #include <algorithm>
19 : #include <cmath>
20 : #include <limits>
21 :
22 : namespace
23 : {
24 :
25 4 : TEST(TestFloat16, conversions)
26 : {
27 4098 : for (int i = -2048; i <= +2048; ++i)
28 : {
29 4097 : EXPECT_EQ(GFloat16(i), static_cast<double>(i));
30 4097 : if (i >= -128 && i <= 127)
31 : {
32 256 : EXPECT_EQ(GFloat16(static_cast<signed char>(i)),
33 : static_cast<double>(i));
34 : }
35 4097 : EXPECT_EQ(GFloat16(static_cast<short>(i)), static_cast<double>(i));
36 4097 : EXPECT_EQ(GFloat16(static_cast<int>(i)), static_cast<double>(i));
37 4097 : EXPECT_EQ(GFloat16(static_cast<long>(i)), static_cast<double>(i));
38 4097 : EXPECT_EQ(GFloat16(static_cast<long long>(i)), static_cast<double>(i));
39 4097 : if (i >= 0)
40 : {
41 2049 : if (i <= 255)
42 : {
43 256 : EXPECT_EQ(GFloat16(static_cast<unsigned char>(i)),
44 : static_cast<double>(i));
45 : }
46 2049 : EXPECT_EQ(GFloat16(static_cast<unsigned short>(i)),
47 : static_cast<double>(i));
48 2049 : EXPECT_EQ(GFloat16(static_cast<unsigned>(i)),
49 : static_cast<double>(i));
50 2049 : EXPECT_EQ(GFloat16(static_cast<unsigned long>(i)),
51 : static_cast<double>(i));
52 2049 : EXPECT_EQ(GFloat16(static_cast<unsigned long long>(i)),
53 : static_cast<double>(i));
54 : }
55 4097 : EXPECT_EQ(GFloat16(i), GFloat16(i));
56 4097 : EXPECT_EQ(GFloat16(i), static_cast<double>(i));
57 : }
58 :
59 1 : EXPECT_EQ(GFloat16(65504), 65504.0);
60 1 : EXPECT_EQ(GFloat16(-65504), -65504.0);
61 : // Work around the Windows compiler reporting "error C2124: divide
62 : // or mod by zero". See also
63 : // <https://stackoverflow.com/questions/3082508/msvc-erroring-on-a-divide-by-0-that-will-never-happen-fix>.
64 1 : volatile double zero = 0.0;
65 1 : EXPECT_EQ(GFloat16(1.0 / zero), 1.0 / zero);
66 1 : EXPECT_EQ(GFloat16(-1.0 / zero), -1.0 / zero);
67 1 : EXPECT_EQ(GFloat16(0.0), -0.0);
68 1 : EXPECT_EQ(GFloat16(-0.0), 0.0);
69 1 : }
70 :
71 4 : TEST(TestFloat16, arithmetic)
72 : {
73 202 : for (int i = -100; i <= +100; ++i)
74 : {
75 201 : double x = i;
76 :
77 201 : EXPECT_EQ(+GFloat16(x), +x);
78 201 : EXPECT_EQ(-GFloat16(x), -x);
79 : }
80 :
81 202 : for (int i = -100; i <= +100; ++i)
82 : {
83 40602 : for (int j = -100; j <= +100; ++j)
84 : {
85 40401 : double x = i;
86 40401 : double y = j;
87 :
88 40401 : EXPECT_EQ(GFloat16(x) + GFloat16(y), x + y);
89 40401 : EXPECT_EQ(GFloat16(x) - GFloat16(y), x - y);
90 : using std::fabs;
91 40401 : EXPECT_NEAR(GFloat16(x) * GFloat16(y), x * y, fabs(x * y / 1024));
92 40401 : if (j != 0)
93 : {
94 40200 : EXPECT_NEAR(GFloat16(x) / GFloat16(y), x / y,
95 : fabs(x / y / 1024));
96 : }
97 : }
98 : }
99 1 : }
100 :
101 4 : TEST(TestFloat16, comparisons)
102 : {
103 202 : for (int i = -100; i <= +100; ++i)
104 : {
105 40602 : for (int j = -100; j <= +100; ++j)
106 : {
107 40401 : double x = i;
108 40401 : double y = j;
109 :
110 40401 : EXPECT_EQ(GFloat16(x) == GFloat16(y), x == y);
111 40401 : EXPECT_EQ(GFloat16(x) != GFloat16(y), x != y);
112 40401 : EXPECT_EQ(GFloat16(x) < GFloat16(y), x < y);
113 40401 : EXPECT_EQ(GFloat16(x) > GFloat16(y), x > y);
114 40401 : EXPECT_EQ(GFloat16(x) <= GFloat16(y), x <= y);
115 40401 : EXPECT_EQ(GFloat16(x) >= GFloat16(y), x >= y);
116 : }
117 : }
118 1 : }
119 :
120 4 : TEST(TestFloat16, math)
121 : {
122 202 : for (int i = -100; i <= +100; ++i)
123 : {
124 201 : const double x = i;
125 :
126 : using std::isfinite;
127 201 : EXPECT_EQ(isfinite(GFloat16(x)), isfinite(x));
128 : using std::isinf;
129 201 : EXPECT_EQ(isinf(GFloat16(x)), isinf(x));
130 : using std::isnan;
131 201 : EXPECT_EQ(isnan(GFloat16(x)), isnan(x));
132 : using std::abs;
133 201 : EXPECT_EQ(abs(GFloat16(x)), abs(x));
134 : using std::cbrt;
135 : using std::fabs;
136 201 : EXPECT_NEAR(cbrt(GFloat16(x)), cbrt(x), fabs(cbrt(x) / 1024));
137 : using std::ceil;
138 201 : EXPECT_EQ(ceil(GFloat16(x)), ceil(x));
139 : using std::fabs;
140 201 : EXPECT_EQ(fabs(GFloat16(x)), fabs(x));
141 : using std::floor;
142 201 : EXPECT_EQ(floor(GFloat16(x)), floor(x));
143 : using std::round;
144 201 : EXPECT_EQ(round(GFloat16(x)), round(x));
145 : }
146 102 : for (int i = 0; i <= 100; ++i)
147 : {
148 101 : const double x = i;
149 : using std::sqrt;
150 101 : EXPECT_NEAR(sqrt(GFloat16(x)), sqrt(x), fabs(sqrt(x) / 1024));
151 : }
152 :
153 : // To avoid Coverity Scan false positive about first value not positive...
154 80802 : const auto myPow = [](int a, int b)
155 : {
156 80802 : double res = 1.0;
157 4141000 : for (int k = 0; k < std::abs(b); ++k)
158 4060200 : res *= a;
159 80802 : if (b >= 0)
160 40602 : return res;
161 40200 : else if (a == 0)
162 200 : return std::numeric_limits<double>::infinity();
163 : else
164 40000 : return 1.0 / res;
165 : };
166 :
167 202 : for (int i = -100; i <= +100; ++i)
168 : {
169 40602 : for (int j = -100; j <= +100; ++j)
170 : {
171 40401 : const double x = i;
172 40401 : const double y = j;
173 :
174 : using std::fmax;
175 40401 : EXPECT_EQ(fmax(GFloat16(x), GFloat16(y)), GFloat16(fmax(x, y)));
176 : using std::fmin;
177 40401 : EXPECT_EQ(fmin(GFloat16(x), GFloat16(y)), GFloat16(fmin(x, y)));
178 : using std::hypot;
179 40401 : EXPECT_EQ(hypot(GFloat16(x), GFloat16(y)), GFloat16(hypot(x, y)));
180 : using std::max;
181 40401 : EXPECT_EQ(max(GFloat16(x), GFloat16(y)), GFloat16(max(x, y)));
182 : using std::min;
183 40401 : EXPECT_EQ(min(GFloat16(x), GFloat16(y)), GFloat16(min(x, y)));
184 : using std::pow;
185 40401 : EXPECT_EQ(pow(GFloat16(x), GFloat16(y)), GFloat16(myPow(i, j)))
186 0 : << "i=" << i << ", j=" << j;
187 : using std::fabs;
188 : using std::isfinite;
189 40401 : GFloat16 r1 = GFloat16(pow(GFloat16(x), j));
190 40401 : GFloat16 r2 = GFloat16(myPow(i, j));
191 40401 : if (!isfinite(r1))
192 : {
193 19344 : EXPECT_EQ(r1, r2);
194 : }
195 : else
196 : {
197 21057 : GFloat16 tol = (1 + fabs(r2)) / 1024;
198 21057 : EXPECT_NEAR(r1, r2, tol);
199 : }
200 : }
201 : }
202 1 : }
203 :
204 : } // namespace
|