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 :
21 : namespace
22 : {
23 :
24 4 : TEST(TestFloat16, conversions)
25 : {
26 4098 : for (int i = -2048; i <= +2048; ++i)
27 : {
28 4097 : EXPECT_EQ(GFloat16(i), static_cast<double>(i));
29 4097 : if (i >= -128 && i <= 127)
30 : {
31 256 : EXPECT_EQ(GFloat16(static_cast<signed char>(i)),
32 : static_cast<double>(i));
33 : }
34 4097 : EXPECT_EQ(GFloat16(static_cast<short>(i)), static_cast<double>(i));
35 4097 : EXPECT_EQ(GFloat16(static_cast<int>(i)), static_cast<double>(i));
36 4097 : EXPECT_EQ(GFloat16(static_cast<long>(i)), static_cast<double>(i));
37 4097 : EXPECT_EQ(GFloat16(static_cast<long long>(i)), static_cast<double>(i));
38 4097 : if (i >= 0)
39 : {
40 2049 : if (i <= 255)
41 : {
42 256 : EXPECT_EQ(GFloat16(static_cast<unsigned char>(i)),
43 : static_cast<double>(i));
44 : }
45 2049 : EXPECT_EQ(GFloat16(static_cast<unsigned short>(i)),
46 : static_cast<double>(i));
47 2049 : EXPECT_EQ(GFloat16(static_cast<unsigned>(i)),
48 : static_cast<double>(i));
49 2049 : EXPECT_EQ(GFloat16(static_cast<unsigned long>(i)),
50 : static_cast<double>(i));
51 2049 : EXPECT_EQ(GFloat16(static_cast<unsigned long long>(i)),
52 : static_cast<double>(i));
53 : }
54 4097 : EXPECT_EQ(GFloat16(i), GFloat16(i));
55 4097 : EXPECT_EQ(GFloat16(i), static_cast<double>(i));
56 : }
57 :
58 1 : EXPECT_EQ(GFloat16(65504), 65504.0);
59 1 : EXPECT_EQ(GFloat16(-65504), -65504.0);
60 : // Work around the Windows compiler reporting "error C2124: divide
61 : // or mod by zero". See also
62 : // <https://stackoverflow.com/questions/3082508/msvc-erroring-on-a-divide-by-0-that-will-never-happen-fix>.
63 1 : volatile double zero = 0.0;
64 1 : EXPECT_EQ(GFloat16(1.0 / zero), 1.0 / zero);
65 1 : EXPECT_EQ(GFloat16(-1.0 / zero), -1.0 / zero);
66 1 : EXPECT_EQ(GFloat16(0.0), -0.0);
67 1 : EXPECT_EQ(GFloat16(-0.0), 0.0);
68 1 : }
69 :
70 4 : TEST(TestFloat16, arithmetic)
71 : {
72 202 : for (int i = -100; i <= +100; ++i)
73 : {
74 201 : double x = i;
75 :
76 201 : EXPECT_EQ(+GFloat16(x), +x);
77 201 : EXPECT_EQ(-GFloat16(x), -x);
78 : }
79 :
80 202 : for (int i = -100; i <= +100; ++i)
81 : {
82 40602 : for (int j = -100; j <= +100; ++j)
83 : {
84 40401 : double x = i;
85 40401 : double y = j;
86 :
87 40401 : EXPECT_EQ(GFloat16(x) + GFloat16(y), x + y);
88 40401 : EXPECT_EQ(GFloat16(x) - GFloat16(y), x - y);
89 : using std::fabs;
90 40401 : EXPECT_NEAR(GFloat16(x) * GFloat16(y), x * y, fabs(x * y / 1024));
91 40401 : if (j != 0)
92 : {
93 40200 : EXPECT_NEAR(GFloat16(x) / GFloat16(y), x / y,
94 : fabs(x / y / 1024));
95 : }
96 : }
97 : }
98 1 : }
99 :
100 4 : TEST(TestFloat16, comparisons)
101 : {
102 202 : for (int i = -100; i <= +100; ++i)
103 : {
104 40602 : for (int j = -100; j <= +100; ++j)
105 : {
106 40401 : double x = i;
107 40401 : double y = j;
108 :
109 40401 : EXPECT_EQ(GFloat16(x) == GFloat16(y), x == y);
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 : }
116 : }
117 1 : }
118 :
119 4 : TEST(TestFloat16, math)
120 : {
121 202 : for (int i = -100; i <= +100; ++i)
122 : {
123 201 : double x = i;
124 :
125 : using std::isfinite;
126 201 : EXPECT_EQ(isfinite(GFloat16(x)), isfinite(x));
127 : using std::isinf;
128 201 : EXPECT_EQ(isinf(GFloat16(x)), isinf(x));
129 : using std::isnan;
130 201 : EXPECT_EQ(isnan(GFloat16(x)), isnan(x));
131 : using std::abs;
132 201 : EXPECT_EQ(abs(GFloat16(x)), abs(x));
133 : using std::cbrt;
134 : using std::fabs;
135 201 : EXPECT_NEAR(cbrt(GFloat16(x)), cbrt(x), fabs(cbrt(x) / 1024));
136 : using std::ceil;
137 201 : EXPECT_EQ(ceil(GFloat16(x)), ceil(x));
138 : using std::fabs;
139 201 : EXPECT_EQ(fabs(GFloat16(x)), fabs(x));
140 : using std::floor;
141 201 : EXPECT_EQ(floor(GFloat16(x)), floor(x));
142 : using std::round;
143 201 : EXPECT_EQ(round(GFloat16(x)), round(x));
144 201 : if (x >= 0)
145 : {
146 : using std::sqrt;
147 101 : EXPECT_NEAR(sqrt(GFloat16(x)), sqrt(x), fabs(sqrt(x) / 1024));
148 : }
149 : }
150 :
151 202 : for (int i = -100; i <= +100; ++i)
152 : {
153 40602 : for (int j = -100; j <= +100; ++j)
154 : {
155 40401 : double x = i;
156 40401 : double y = j;
157 :
158 : using std::fmax;
159 40401 : EXPECT_EQ(fmax(GFloat16(x), GFloat16(y)), GFloat16(fmax(x, y)));
160 : using std::fmin;
161 40401 : EXPECT_EQ(fmin(GFloat16(x), GFloat16(y)), GFloat16(fmin(x, y)));
162 : using std::hypot;
163 40401 : EXPECT_EQ(hypot(GFloat16(x), GFloat16(y)), GFloat16(hypot(x, y)));
164 : using std::max;
165 40401 : EXPECT_EQ(max(GFloat16(x), GFloat16(y)), GFloat16(max(x, y)));
166 : using std::min;
167 40401 : EXPECT_EQ(min(GFloat16(x), GFloat16(y)), GFloat16(min(x, y)));
168 : using std::pow;
169 40401 : EXPECT_EQ(pow(GFloat16(x), GFloat16(y)), GFloat16(pow(x, y)));
170 : using std::fabs;
171 : using std::isfinite;
172 40401 : GFloat16 r1 = GFloat16(pow(GFloat16(x), j));
173 40401 : GFloat16 r2 = GFloat16(pow(x, j));
174 40401 : if (!isfinite(r1))
175 : {
176 19344 : EXPECT_EQ(r1, r2);
177 : }
178 : else
179 : {
180 21057 : GFloat16 tol = (1 + fabs(r2)) / 1024;
181 21057 : EXPECT_NEAR(r1, r2, tol);
182 : }
183 : }
184 : }
185 1 : }
186 :
187 : } // namespace
|