1 #include <gtest/gtest.h>
2
3 #include <cstdint>
4
5 #include <fp16.h>
6 #include "tables.h"
7
8
TEST(FP16_IEEE_TO_FP32_BITS,normalized_powers_of_2)9 TEST(FP16_IEEE_TO_FP32_BITS, normalized_powers_of_2) {
10 const uint16_t min_po2_f16 = UINT16_C(0x0400);
11 const uint16_t eighths_f16 = UINT16_C(0x3000);
12 const uint16_t quarter_f16 = UINT16_C(0x3400);
13 const uint16_t half_f16 = UINT16_C(0x3800);
14 const uint16_t one_f16 = UINT16_C(0x3C00);
15 const uint16_t two_f16 = UINT16_C(0x4000);
16 const uint16_t four_f16 = UINT16_C(0x4400);
17 const uint16_t eight_f16 = UINT16_C(0x4800);
18 const uint16_t sixteen_f16 = UINT16_C(0x4C00);
19 const uint16_t thirtytwo_f16 = UINT16_C(0x5000);
20 const uint16_t sixtyfour_f16 = UINT16_C(0x5400);
21 const uint16_t max_po2_f16 = UINT16_C(0x7800);
22
23 const uint32_t min_po2_f32 = UINT32_C(0x38800000);
24 const uint32_t eighths_f32 = UINT32_C(0x3E000000);
25 const uint32_t quarter_f32 = UINT32_C(0x3E800000);
26 const uint32_t half_f32 = UINT32_C(0x3F000000);
27 const uint32_t one_f32 = UINT32_C(0x3F800000);
28 const uint32_t two_f32 = UINT32_C(0x40000000);
29 const uint32_t four_f32 = UINT32_C(0x40800000);
30 const uint32_t eight_f32 = UINT32_C(0x41000000);
31 const uint32_t sixteen_f32 = UINT32_C(0x41800000);
32 const uint32_t thirtytwo_f32 = UINT32_C(0x42000000);
33 const uint32_t sixtyfour_f32 = UINT32_C(0x42800000);
34 const uint32_t max_po2_f32 = UINT32_C(0x47000000);
35
36 EXPECT_EQ(min_po2_f32, fp16_ieee_to_fp32_bits(min_po2_f16)) <<
37 std::hex << std::uppercase << std::setfill('0') <<
38 "F16 = 0x" << std::setw(4) << min_po2_f16 << ", " <<
39 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(min_po2_f16) << ", " <<
40 "F32 = 0x" << std::setw(8) << min_po2_f32;
41
42 EXPECT_EQ(eighths_f32, fp16_ieee_to_fp32_bits(eighths_f16)) <<
43 std::hex << std::uppercase << std::setfill('0') <<
44 "F16 = 0x" << std::setw(4) << eighths_f16 << ", " <<
45 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(eighths_f16) << ", " <<
46 "F32 = 0x" << std::setw(8) << eighths_f32;
47
48 EXPECT_EQ(quarter_f32, fp16_ieee_to_fp32_bits(quarter_f16)) <<
49 std::hex << std::uppercase << std::setfill('0') <<
50 "F16 = 0x" << std::setw(4) << quarter_f16 << ", " <<
51 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(quarter_f16) << ", " <<
52 "F32 = 0x" << std::setw(8) << quarter_f32;
53
54 EXPECT_EQ(half_f32, fp16_ieee_to_fp32_bits(half_f16)) <<
55 std::hex << std::uppercase << std::setfill('0') <<
56 "F16 = 0x" << std::setw(4) << half_f16 << ", " <<
57 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(half_f16) << ", " <<
58 "F32 = 0x" << std::setw(8) << half_f32;
59
60 EXPECT_EQ(one_f32, fp16_ieee_to_fp32_bits(one_f16)) <<
61 std::hex << std::uppercase << std::setfill('0') <<
62 "F16 = 0x" << std::setw(4) << one_f16 << ", " <<
63 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(one_f16) << ", " <<
64 "F32 = 0x" << std::setw(8) << one_f32;
65
66 EXPECT_EQ(two_f32, fp16_ieee_to_fp32_bits(two_f16)) <<
67 std::hex << std::uppercase << std::setfill('0') <<
68 "F16 = 0x" << std::setw(4) << two_f16 << ", " <<
69 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(two_f16) << ", " <<
70 "F32 = 0x" << std::setw(8) << two_f32;
71
72 EXPECT_EQ(four_f32, fp16_ieee_to_fp32_bits(four_f16)) <<
73 std::hex << std::uppercase << std::setfill('0') <<
74 "F16 = 0x" << std::setw(4) << four_f16 << ", " <<
75 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(four_f16) << ", " <<
76 "F32 = 0x" << std::setw(8) << four_f32;
77
78 EXPECT_EQ(eight_f32, fp16_ieee_to_fp32_bits(eight_f16)) <<
79 std::hex << std::uppercase << std::setfill('0') <<
80 "F16 = 0x" << std::setw(4) << eight_f16 << ", " <<
81 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(eight_f16) << ", " <<
82 "F32 = 0x" << std::setw(8) << eight_f32;
83
84 EXPECT_EQ(sixteen_f32, fp16_ieee_to_fp32_bits(sixteen_f16)) <<
85 std::hex << std::uppercase << std::setfill('0') <<
86 "F16 = 0x" << std::setw(4) << sixteen_f16 << ", " <<
87 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(sixteen_f16) << ", " <<
88 "F32 = 0x" << std::setw(8) << sixteen_f32;
89
90 EXPECT_EQ(thirtytwo_f32, fp16_ieee_to_fp32_bits(thirtytwo_f16)) <<
91 std::hex << std::uppercase << std::setfill('0') <<
92 "F16 = 0x" << std::setw(4) << thirtytwo_f16 << ", " <<
93 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(thirtytwo_f16) << ", " <<
94 "F32 = 0x" << std::setw(8) << thirtytwo_f32;
95
96 EXPECT_EQ(sixtyfour_f32, fp16_ieee_to_fp32_bits(sixtyfour_f16)) <<
97 std::hex << std::uppercase << std::setfill('0') <<
98 "F16 = 0x" << std::setw(4) << sixtyfour_f16 << ", " <<
99 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(sixtyfour_f16) << ", " <<
100 "F32 = 0x" << std::setw(8) << sixtyfour_f32;
101
102 EXPECT_EQ(max_po2_f32, fp16_ieee_to_fp32_bits(max_po2_f16)) <<
103 std::hex << std::uppercase << std::setfill('0') <<
104 "F16 = 0x" << std::setw(4) << max_po2_f16 << ", " <<
105 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(max_po2_f16) << ", " <<
106 "F32 = 0x" << std::setw(8) << max_po2_f32;
107 }
108
TEST(FP16_IEEE_TO_FP32_BITS,denormalized_powers_of_2)109 TEST(FP16_IEEE_TO_FP32_BITS, denormalized_powers_of_2) {
110 const uint16_t exp2_minus_15_f16 = UINT16_C(0x0200);
111 const uint16_t exp2_minus_16_f16 = UINT16_C(0x0100);
112 const uint16_t exp2_minus_17_f16 = UINT16_C(0x0080);
113 const uint16_t exp2_minus_18_f16 = UINT16_C(0x0040);
114 const uint16_t exp2_minus_19_f16 = UINT16_C(0x0020);
115 const uint16_t exp2_minus_20_f16 = UINT16_C(0x0010);
116 const uint16_t exp2_minus_21_f16 = UINT16_C(0x0008);
117 const uint16_t exp2_minus_22_f16 = UINT16_C(0x0004);
118 const uint16_t exp2_minus_23_f16 = UINT16_C(0x0002);
119 const uint16_t exp2_minus_24_f16 = UINT16_C(0x0001);
120
121 const uint32_t exp2_minus_15_f32 = UINT32_C(0x38000000);
122 const uint32_t exp2_minus_16_f32 = UINT32_C(0x37800000);
123 const uint32_t exp2_minus_17_f32 = UINT32_C(0x37000000);
124 const uint32_t exp2_minus_18_f32 = UINT32_C(0x36800000);
125 const uint32_t exp2_minus_19_f32 = UINT32_C(0x36000000);
126 const uint32_t exp2_minus_20_f32 = UINT32_C(0x35800000);
127 const uint32_t exp2_minus_21_f32 = UINT32_C(0x35000000);
128 const uint32_t exp2_minus_22_f32 = UINT32_C(0x34800000);
129 const uint32_t exp2_minus_23_f32 = UINT32_C(0x34000000);
130 const uint32_t exp2_minus_24_f32 = UINT32_C(0x33800000);
131
132 EXPECT_EQ(exp2_minus_15_f32, fp16_ieee_to_fp32_bits(exp2_minus_15_f16)) <<
133 std::hex << std::uppercase << std::setfill('0') <<
134 "F16 = 0x" << std::setw(4) << exp2_minus_15_f16 << ", " <<
135 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(exp2_minus_15_f16) << ", " <<
136 "F32 = 0x" << std::setw(8) << exp2_minus_15_f32;
137
138 EXPECT_EQ(exp2_minus_16_f32, fp16_ieee_to_fp32_bits(exp2_minus_16_f16)) <<
139 std::hex << std::uppercase << std::setfill('0') <<
140 "F16 = 0x" << std::setw(4) << exp2_minus_16_f16 << ", " <<
141 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(exp2_minus_16_f16) << ", " <<
142 "F32 = 0x" << std::setw(8) << exp2_minus_16_f32;
143
144 EXPECT_EQ(exp2_minus_17_f32, fp16_ieee_to_fp32_bits(exp2_minus_17_f16)) <<
145 std::hex << std::uppercase << std::setfill('0') <<
146 "F16 = 0x" << std::setw(4) << exp2_minus_17_f16 << ", " <<
147 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(exp2_minus_17_f16) << ", " <<
148 "F32 = 0x" << std::setw(8) << exp2_minus_17_f32;
149
150 EXPECT_EQ(exp2_minus_18_f32, fp16_ieee_to_fp32_bits(exp2_minus_18_f16)) <<
151 std::hex << std::uppercase << std::setfill('0') <<
152 "F16 = 0x" << std::setw(4) << exp2_minus_18_f16 << ", " <<
153 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(exp2_minus_18_f16) << ", " <<
154 "F32 = 0x" << std::setw(8) << exp2_minus_18_f32;
155
156 EXPECT_EQ(exp2_minus_19_f32, fp16_ieee_to_fp32_bits(exp2_minus_19_f16)) <<
157 std::hex << std::uppercase << std::setfill('0') <<
158 "F16 = 0x" << std::setw(4) << exp2_minus_19_f16 << ", " <<
159 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(exp2_minus_19_f16) << ", " <<
160 "F32 = 0x" << std::setw(8) << exp2_minus_19_f32;
161
162 EXPECT_EQ(exp2_minus_20_f32, fp16_ieee_to_fp32_bits(exp2_minus_20_f16)) <<
163 std::hex << std::uppercase << std::setfill('0') <<
164 "F16 = 0x" << std::setw(4) << exp2_minus_20_f16 << ", " <<
165 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(exp2_minus_20_f16) << ", " <<
166 "F32 = 0x" << std::setw(8) << exp2_minus_20_f32;
167
168 EXPECT_EQ(exp2_minus_21_f32, fp16_ieee_to_fp32_bits(exp2_minus_21_f16)) <<
169 std::hex << std::uppercase << std::setfill('0') <<
170 "F16 = 0x" << std::setw(4) << exp2_minus_21_f16 << ", " <<
171 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(exp2_minus_21_f16) << ", " <<
172 "F32 = 0x" << std::setw(8) << exp2_minus_21_f32;
173
174 EXPECT_EQ(exp2_minus_22_f32, fp16_ieee_to_fp32_bits(exp2_minus_22_f16)) <<
175 std::hex << std::uppercase << std::setfill('0') <<
176 "F16 = 0x" << std::setw(4) << exp2_minus_22_f16 << ", " <<
177 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(exp2_minus_22_f16) << ", " <<
178 "F32 = 0x" << std::setw(8) << exp2_minus_22_f32;
179
180 EXPECT_EQ(exp2_minus_23_f32, fp16_ieee_to_fp32_bits(exp2_minus_23_f16)) <<
181 std::hex << std::uppercase << std::setfill('0') <<
182 "F16 = 0x" << std::setw(4) << exp2_minus_23_f16 << ", " <<
183 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(exp2_minus_23_f16) << ", " <<
184 "F32 = 0x" << std::setw(8) << exp2_minus_23_f32;
185
186 EXPECT_EQ(exp2_minus_24_f32, fp16_ieee_to_fp32_bits(exp2_minus_24_f16)) <<
187 std::hex << std::uppercase << std::setfill('0') <<
188 "F16 = 0x" << std::setw(4) << exp2_minus_24_f16 << ", " <<
189 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(exp2_minus_24_f16) << ", " <<
190 "F32 = 0x" << std::setw(8) << exp2_minus_24_f32;
191 }
192
TEST(FP16_IEEE_TO_FP32_BITS,zero)193 TEST(FP16_IEEE_TO_FP32_BITS, zero) {
194 const uint16_t positive_zero_f16 = UINT16_C(0x0000);
195 const uint16_t negative_zero_f16 = UINT16_C(0x8000);
196
197 const uint32_t positive_zero_f32 = UINT32_C(0x00000000);
198 const uint32_t negative_zero_f32 = UINT32_C(0x80000000);
199
200 EXPECT_EQ(positive_zero_f32, fp16_ieee_to_fp32_bits(positive_zero_f16)) <<
201 std::hex << std::uppercase << std::setfill('0') <<
202 "F16 = 0x" << std::setw(4) << positive_zero_f16 << ", " <<
203 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(positive_zero_f16) << ", " <<
204 "F32 = 0x" << std::setw(8) << positive_zero_f32;
205
206 EXPECT_EQ(negative_zero_f32, fp16_ieee_to_fp32_bits(negative_zero_f16)) <<
207 std::hex << std::uppercase << std::setfill('0') <<
208 "F16 = 0x" << std::setw(4) << negative_zero_f16 << ", " <<
209 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(negative_zero_f16) << ", " <<
210 "F32 = 0x" << std::setw(8) << negative_zero_f32;
211 }
212
TEST(FP16_IEEE_TO_FP32_BITS,infinity)213 TEST(FP16_IEEE_TO_FP32_BITS, infinity) {
214 const uint16_t positive_infinity_f16 = UINT16_C(0x7C00);
215 const uint16_t negative_infinity_f16 = UINT16_C(0xFC00);
216
217 const uint32_t positive_infinity_f32 = UINT32_C(0x7F800000);
218 const uint32_t negative_infinity_f32 = UINT32_C(0xFF800000);
219
220 EXPECT_EQ(positive_infinity_f32, fp16_ieee_to_fp32_bits(positive_infinity_f16)) <<
221 std::hex << std::uppercase << std::setfill('0') <<
222 "F16 = 0x" << std::setw(4) << positive_infinity_f16 << ", " <<
223 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(positive_infinity_f16) << ", " <<
224 "F32 = 0x" << std::setw(8) << positive_infinity_f32;
225
226 EXPECT_EQ(negative_infinity_f32, fp16_ieee_to_fp32_bits(negative_infinity_f16)) <<
227 std::hex << std::uppercase << std::setfill('0') <<
228 "F16 = 0x" << std::setw(4) << negative_infinity_f16 << ", " <<
229 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(negative_infinity_f16) << ", " <<
230 "F32 = 0x" << std::setw(8) << negative_infinity_f32;
231 }
232
TEST(FP16_IEEE_TO_FP32_BITS,positive_nan)233 TEST(FP16_IEEE_TO_FP32_BITS, positive_nan) {
234 for (uint16_t m = UINT16_C(1); m < UINT16_C(0x0400); m++) {
235 const uint16_t nan_f16 = UINT16_C(0x7C00) | m;
236 const uint32_t nan_f32 = fp16_ieee_to_fp32_bits(nan_f16);
237
238 /* Check sign */
239 EXPECT_EQ(nan_f32 & UINT32_C(0x80000000), 0) <<
240 std::hex << std::uppercase << std::setfill('0') <<
241 "F16 = 0x" << std::setw(4) << nan_f16 << ", " <<
242 "F32(F16) = 0x" << std::setw(8) << nan_f32;
243
244 /* Check exponent */
245 EXPECT_EQ(nan_f32 & UINT32_C(0x7F800000), UINT32_C(0x7F800000)) <<
246 std::hex << std::uppercase << std::setfill('0') <<
247 "F16 = 0x" << std::setw(4) << nan_f16 << ", " <<
248 "F32(F16) = 0x" << std::setw(8) << nan_f32;
249
250 /* Check mantissa */
251 EXPECT_NE(nan_f32 & UINT32_C(0x007FFFFF), UINT32_C(0)) <<
252 std::hex << std::uppercase << std::setfill('0') <<
253 "F16 = 0x" << std::setw(4) << nan_f16 << ", " <<
254 "F32(F16) = 0x" << std::setw(8) << nan_f32;
255 }
256 }
257
TEST(FP16_IEEE_TO_FP32_BITS,negative_nan)258 TEST(FP16_IEEE_TO_FP32_BITS, negative_nan) {
259 for (uint16_t m = UINT16_C(1); m < UINT16_C(0x0400); m++) {
260 const uint16_t nan_f16 = UINT16_C(0xFC00) | m;
261 const uint32_t nan_f32 = fp16_ieee_to_fp32_bits(nan_f16);
262
263 /* Check sign */
264 EXPECT_NE(nan_f32 & UINT32_C(0x80000000), UINT32_C(0)) <<
265 std::hex << std::uppercase << std::setfill('0') <<
266 "F16 = 0x" << std::setw(4) << nan_f16 << ", " <<
267 "F32(F16) = 0x" << std::setw(8) << nan_f32;
268
269 /* Check exponent */
270 EXPECT_EQ(nan_f32 & UINT32_C(0x7F800000), UINT32_C(0x7F800000)) <<
271 std::hex << std::uppercase << std::setfill('0') <<
272 "F16 = 0x" << std::setw(4) << nan_f16 << ", " <<
273 "F32(F16) = 0x" << std::setw(8) << nan_f32;
274
275 /* Check mantissa */
276 EXPECT_NE(nan_f32 & UINT32_C(0x007FFFFF), UINT32_C(0)) <<
277 std::hex << std::uppercase << std::setfill('0') <<
278 "F16 = 0x" << std::setw(4) << nan_f16 << ", " <<
279 "F32(F16) = 0x" << std::setw(8) << nan_f32;
280 }
281 }
282
TEST(FP16_IEEE_TO_FP32_BITS,positive_normalized_values)283 TEST(FP16_IEEE_TO_FP32_BITS, positive_normalized_values) {
284 const uint32_t exponentBias = 15;
285 for (int32_t e = -14; e <= 15; e++) {
286 for (uint16_t h = 0; h < 0x0400; h++) {
287 const uint16_t fp16 = h + ((uint16_t) (e + exponentBias) << 10);
288 const uint32_t fp32 = fp16::normalizedValues[h] + ((uint32_t) e << 23);
289 EXPECT_EQ(fp32, fp16_ieee_to_fp32_bits(fp16)) <<
290 std::hex << std::uppercase << std::setfill('0') <<
291 "F16 = 0x" << std::setw(4) << fp16 << ", " <<
292 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16) << ", " <<
293 "F32 = 0x" << std::setw(8) << fp32;
294 }
295 }
296 }
297
TEST(FP16_IEEE_TO_FP32_BITS,negative_normalized_values)298 TEST(FP16_IEEE_TO_FP32_BITS, negative_normalized_values) {
299 const uint32_t exponentBias = 15;
300 for (int32_t e = -14; e <= 15; e++) {
301 for (uint16_t h = 0; h < 0x0400; h++) {
302 const uint16_t fp16 = (h + ((uint16_t) (e + exponentBias) << 10)) ^ UINT16_C(0x8000);
303 const uint32_t fp32 = (fp16::normalizedValues[h] + ((uint32_t) e << 23)) ^ UINT32_C(0x80000000);
304 EXPECT_EQ(fp32, fp16_ieee_to_fp32_bits(fp16)) <<
305 std::hex << std::uppercase << std::setfill('0') <<
306 "F16 = 0x" << std::setw(4) << fp16 << ", " <<
307 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16) << ", " <<
308 "F32 = 0x" << std::setw(8) << fp32;
309 }
310 }
311 }
312
TEST(FP16_IEEE_TO_FP32_BITS,positive_denormalized_values)313 TEST(FP16_IEEE_TO_FP32_BITS, positive_denormalized_values) {
314 for (uint16_t h = 0; h < 0x0400; h++) {
315 EXPECT_EQ(fp16::denormalizedValues[h], fp16_ieee_to_fp32_bits(h)) <<
316 std::hex << std::uppercase << std::setfill('0') <<
317 "F16 = 0x" << std::setw(4) << h << ", " <<
318 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(h) << ", " <<
319 "F32 = 0x" << std::setw(8) << fp16::denormalizedValues[h];
320 }
321 }
322
TEST(FP16_IEEE_TO_FP32_BITS,negative_denormalized_values)323 TEST(FP16_IEEE_TO_FP32_BITS, negative_denormalized_values) {
324 for (uint16_t h = 0; h < 0x0400; h++) {
325 const uint16_t fp16 = h ^ UINT16_C(0x8000);
326 const uint32_t fp32 = fp16::denormalizedValues[h] ^ UINT32_C(0x80000000);
327 EXPECT_EQ(fp32, fp16_ieee_to_fp32_bits(fp16)) <<
328 std::hex << std::uppercase << std::setfill('0') <<
329 "F16 = 0x" << std::setw(4) << fp16 << ", " <<
330 "F32(F16) = 0x" << std::setw(8) << fp16_ieee_to_fp32_bits(fp16) << ", " <<
331 "F32 = 0x" << std::setw(8) << fp32;
332 }
333 }
334