blob: b8272f6225065cd757a48f945ef3b3592a456832 [file] [log] [blame]
Marat Dukhan7ae046d2017-02-16 16:57:21 -05001#include <gtest/gtest.h>
2
3#include <cstdint>
4
5#include <fp16.h>
Miao Wang0391e512020-02-10 14:52:24 -08006#include "tables.h"
Marat Dukhan7ae046d2017-02-16 16:57:21 -05007
8#if (defined(__i386__) || defined(__x86_64__)) && defined(__F16C__)
9 #include <x86intrin.h>
10#endif
11
Marat Dukhanc6a15ea2017-02-17 12:40:14 -050012
Marat Dukhan7ae046d2017-02-16 16:57:21 -050013TEST(FP16_ALT_FROM_FP32_VALUE, normalized_powers_of_2) {
14 const uint16_t min_po2_f16 = UINT16_C(0x0400);
15 const uint16_t eighths_f16 = UINT16_C(0x3000);
16 const uint16_t quarter_f16 = UINT16_C(0x3400);
17 const uint16_t half_f16 = UINT16_C(0x3800);
18 const uint16_t one_f16 = UINT16_C(0x3C00);
19 const uint16_t two_f16 = UINT16_C(0x4000);
20 const uint16_t four_f16 = UINT16_C(0x4400);
21 const uint16_t eight_f16 = UINT16_C(0x4800);
22 const uint16_t sixteen_f16 = UINT16_C(0x4C00);
23 const uint16_t thirtytwo_f16 = UINT16_C(0x5000);
24 const uint16_t sixtyfour_f16 = UINT16_C(0x5400);
25 const uint16_t max_po2_f16 = UINT16_C(0x7C00);
26
27 const uint32_t min_po2_f32 = UINT32_C(0x38800000);
28 const uint32_t eighths_f32 = UINT32_C(0x3E000000);
29 const uint32_t quarter_f32 = UINT32_C(0x3E800000);
30 const uint32_t half_f32 = UINT32_C(0x3F000000);
31 const uint32_t one_f32 = UINT32_C(0x3F800000);
32 const uint32_t two_f32 = UINT32_C(0x40000000);
33 const uint32_t four_f32 = UINT32_C(0x40800000);
34 const uint32_t eight_f32 = UINT32_C(0x41000000);
35 const uint32_t sixteen_f32 = UINT32_C(0x41800000);
36 const uint32_t thirtytwo_f32 = UINT32_C(0x42000000);
37 const uint32_t sixtyfour_f32 = UINT32_C(0x42800000);
38 const uint32_t max_po2_f32 = UINT32_C(0x47800000);
39
40 float min_po2_value;
41 memcpy(&min_po2_value, &min_po2_f32, sizeof(min_po2_value));
42 EXPECT_EQ(min_po2_f16, fp16_alt_from_fp32_value(min_po2_value)) <<
43 std::hex << std::uppercase << std::setfill('0') <<
44 "F32 = 0x" << std::setw(8) << min_po2_f32 << ", " <<
45 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(min_po2_value) << ", " <<
46 "F16 = 0x" << std::setw(4) << min_po2_f16;
47
48 float eighths_value;
49 memcpy(&eighths_value, &eighths_f32, sizeof(eighths_value));
50 EXPECT_EQ(eighths_f16, fp16_alt_from_fp32_value(eighths_value)) <<
51 std::hex << std::uppercase << std::setfill('0') <<
52 "F32 = 0x" << std::setw(8) << eighths_f32 << ", " <<
53 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(eighths_value) << ", " <<
54 "F16 = 0x" << std::setw(4) << eighths_f16;
55
56 float quarter_value;
57 memcpy(&quarter_value, &quarter_f32, sizeof(quarter_value));
58 EXPECT_EQ(quarter_f16, fp16_alt_from_fp32_value(quarter_value)) <<
59 std::hex << std::uppercase << std::setfill('0') <<
60 "F32 = 0x" << std::setw(8) << quarter_f32 << ", " <<
61 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(quarter_value) << ", " <<
62 "F16 = 0x" << std::setw(4) << quarter_f16;
63
64 float half_value;
65 memcpy(&half_value, &half_f32, sizeof(half_value));
66 EXPECT_EQ(half_f16, fp16_alt_from_fp32_value(half_value)) <<
67 std::hex << std::uppercase << std::setfill('0') <<
68 "F32 = 0x" << std::setw(8) << half_f32 << ", " <<
69 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(half_value) << ", " <<
70 "F16 = 0x" << std::setw(4) << half_f16;
71
72 float one_value;
73 memcpy(&one_value, &one_f32, sizeof(one_value));
74 EXPECT_EQ(one_f16, fp16_alt_from_fp32_value(one_value)) <<
75 std::hex << std::uppercase << std::setfill('0') <<
76 "F32 = 0x" << std::setw(8) << one_f32 << ", " <<
77 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(one_value) << ", " <<
78 "F16 = 0x" << std::setw(4) << one_f16;
79
80 float two_value;
81 memcpy(&two_value, &two_f32, sizeof(two_value));
82 EXPECT_EQ(two_f16, fp16_alt_from_fp32_value(two_value)) <<
83 std::hex << std::uppercase << std::setfill('0') <<
84 "F32 = 0x" << std::setw(8) << two_f32 << ", " <<
85 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(two_value) << ", " <<
86 "F16 = 0x" << std::setw(4) << two_f16;
87
88 float four_value;
89 memcpy(&four_value, &four_f32, sizeof(four_value));
90 EXPECT_EQ(four_f16, fp16_alt_from_fp32_value(four_value)) <<
91 std::hex << std::uppercase << std::setfill('0') <<
92 "F32 = 0x" << std::setw(8) << four_f32 << ", " <<
93 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(four_value) << ", " <<
94 "F16 = 0x" << std::setw(4) << four_f16;
95
96 float eight_value;
97 memcpy(&eight_value, &eight_f32, sizeof(eight_value));
98 EXPECT_EQ(eight_f16, fp16_alt_from_fp32_value(eight_value)) <<
99 std::hex << std::uppercase << std::setfill('0') <<
100 "F32 = 0x" << std::setw(8) << eight_f32 << ", " <<
101 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(eight_value) << ", " <<
102 "F16 = 0x" << std::setw(4) << eight_f16;
103
104 float sixteen_value;
105 memcpy(&sixteen_value, &sixteen_f32, sizeof(sixteen_value));
106 EXPECT_EQ(sixteen_f16, fp16_alt_from_fp32_value(sixteen_value)) <<
107 std::hex << std::uppercase << std::setfill('0') <<
108 "F32 = 0x" << std::setw(8) << sixteen_f32 << ", " <<
109 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(sixteen_value) << ", " <<
110 "F16 = 0x" << std::setw(4) << sixteen_f16;
111
112 float thirtytwo_value;
113 memcpy(&thirtytwo_value, &thirtytwo_f32, sizeof(thirtytwo_value));
114 EXPECT_EQ(thirtytwo_f16, fp16_alt_from_fp32_value(thirtytwo_value)) <<
115 std::hex << std::uppercase << std::setfill('0') <<
116 "F32 = 0x" << std::setw(8) << thirtytwo_f32 << ", " <<
117 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(thirtytwo_value) << ", " <<
118 "F16 = 0x" << std::setw(4) << thirtytwo_f16;
119
120 float sixtyfour_value;
121 memcpy(&sixtyfour_value, &sixtyfour_f32, sizeof(sixtyfour_value));
122 EXPECT_EQ(sixtyfour_f16, fp16_alt_from_fp32_value(sixtyfour_value)) <<
123 std::hex << std::uppercase << std::setfill('0') <<
124 "F32 = 0x" << std::setw(8) << sixtyfour_f32 << ", " <<
125 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(sixtyfour_value) << ", " <<
126 "F16 = 0x" << std::setw(4) << sixtyfour_f16;
Marat Dukhan0ea60952017-07-07 23:30:16 -0700127
128 float max_po2_value;
129 memcpy(&max_po2_value, &max_po2_f32, sizeof(max_po2_value));
130 EXPECT_EQ(max_po2_f16, fp16_ieee_from_fp32_value(max_po2_value)) <<
131 std::hex << std::uppercase << std::setfill('0') <<
132 "F32 = 0x" << std::setw(8) << max_po2_f32 << ", " <<
133 "F16(F32) = 0x" << std::setw(4) << fp16_ieee_from_fp32_value(max_po2_value) << ", " <<
134 "F16 = 0x" << std::setw(4) << max_po2_f16;
Marat Dukhan7ae046d2017-02-16 16:57:21 -0500135}
136
137TEST(FP16_ALT_FROM_FP32_VALUE, denormalized_powers_of_2) {
138 const uint16_t exp2_minus_15_f16 = UINT16_C(0x0200);
139 const uint16_t exp2_minus_16_f16 = UINT16_C(0x0100);
140 const uint16_t exp2_minus_17_f16 = UINT16_C(0x0080);
141 const uint16_t exp2_minus_18_f16 = UINT16_C(0x0040);
142 const uint16_t exp2_minus_19_f16 = UINT16_C(0x0020);
143 const uint16_t exp2_minus_20_f16 = UINT16_C(0x0010);
144 const uint16_t exp2_minus_21_f16 = UINT16_C(0x0008);
145 const uint16_t exp2_minus_22_f16 = UINT16_C(0x0004);
146 const uint16_t exp2_minus_23_f16 = UINT16_C(0x0002);
147 const uint16_t exp2_minus_24_f16 = UINT16_C(0x0001);
148 const uint16_t exp2_minus_25_f16 = UINT16_C(0x0000);
149
150 const uint32_t exp2_minus_15_f32 = UINT32_C(0x38000000);
151 const uint32_t exp2_minus_16_f32 = UINT32_C(0x37800000);
152 const uint32_t exp2_minus_17_f32 = UINT32_C(0x37000000);
153 const uint32_t exp2_minus_18_f32 = UINT32_C(0x36800000);
154 const uint32_t exp2_minus_19_f32 = UINT32_C(0x36000000);
155 const uint32_t exp2_minus_20_f32 = UINT32_C(0x35800000);
156 const uint32_t exp2_minus_21_f32 = UINT32_C(0x35000000);
157 const uint32_t exp2_minus_22_f32 = UINT32_C(0x34800000);
158 const uint32_t exp2_minus_23_f32 = UINT32_C(0x34000000);
159 const uint32_t exp2_minus_24_f32 = UINT32_C(0x33800000);
160 const uint32_t exp2_minus_25_f32 = UINT32_C(0x33000000);
161
162 float exp2_minus_15_value;
163 memcpy(&exp2_minus_15_value, &exp2_minus_15_f32, sizeof(exp2_minus_15_value));
164 EXPECT_EQ(exp2_minus_15_f16, fp16_alt_from_fp32_value(exp2_minus_15_value)) <<
165 std::hex << std::uppercase << std::setfill('0') <<
166 "F32 = 0x" << std::setw(8) << exp2_minus_15_f32 << ", " <<
167 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(exp2_minus_15_value) << ", " <<
168 "F16 = 0x" << std::setw(4) << exp2_minus_15_f16;
169
170 float exp2_minus_16_value;
171 memcpy(&exp2_minus_16_value, &exp2_minus_16_f32, sizeof(exp2_minus_16_value));
172 EXPECT_EQ(exp2_minus_16_f16, fp16_alt_from_fp32_value(exp2_minus_16_value)) <<
173 std::hex << std::uppercase << std::setfill('0') <<
174 "F32 = 0x" << std::setw(8) << exp2_minus_16_f32 << ", " <<
175 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(exp2_minus_16_value) << ", " <<
176 "F16 = 0x" << std::setw(4) << exp2_minus_16_f16;
177
178 float exp2_minus_17_value;
179 memcpy(&exp2_minus_17_value, &exp2_minus_17_f32, sizeof(exp2_minus_17_value));
180 EXPECT_EQ(exp2_minus_17_f16, fp16_alt_from_fp32_value(exp2_minus_17_value)) <<
181 std::hex << std::uppercase << std::setfill('0') <<
182 "F32 = 0x" << std::setw(8) << exp2_minus_17_f32 << ", " <<
183 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(exp2_minus_17_value) << ", " <<
184 "F16 = 0x" << std::setw(4) << exp2_minus_17_f16;
185
186 float exp2_minus_18_value;
187 memcpy(&exp2_minus_18_value, &exp2_minus_18_f32, sizeof(exp2_minus_18_value));
188 EXPECT_EQ(exp2_minus_18_f16, fp16_alt_from_fp32_value(exp2_minus_18_value)) <<
189 std::hex << std::uppercase << std::setfill('0') <<
190 "F32 = 0x" << std::setw(8) << exp2_minus_18_f32 << ", " <<
191 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(exp2_minus_18_value) << ", " <<
192 "F16 = 0x" << std::setw(4) << exp2_minus_18_f16;
193
194 float exp2_minus_19_value;
195 memcpy(&exp2_minus_19_value, &exp2_minus_19_f32, sizeof(exp2_minus_19_value));
196 EXPECT_EQ(exp2_minus_19_f16, fp16_alt_from_fp32_value(exp2_minus_19_value)) <<
197 std::hex << std::uppercase << std::setfill('0') <<
198 "F32 = 0x" << std::setw(8) << exp2_minus_19_f32 << ", " <<
199 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(exp2_minus_19_value) << ", " <<
200 "F16 = 0x" << std::setw(4) << exp2_minus_19_f16;
201
202 float exp2_minus_20_value;
203 memcpy(&exp2_minus_20_value, &exp2_minus_20_f32, sizeof(exp2_minus_20_value));
204 EXPECT_EQ(exp2_minus_20_f16, fp16_alt_from_fp32_value(exp2_minus_20_value)) <<
205 std::hex << std::uppercase << std::setfill('0') <<
206 "F32 = 0x" << std::setw(8) << exp2_minus_20_f32 << ", " <<
207 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(exp2_minus_20_value) << ", " <<
208 "F16 = 0x" << std::setw(4) << exp2_minus_20_f16;
209
210 float exp2_minus_21_value;
211 memcpy(&exp2_minus_21_value, &exp2_minus_21_f32, sizeof(exp2_minus_21_value));
212 EXPECT_EQ(exp2_minus_21_f16, fp16_alt_from_fp32_value(exp2_minus_21_value)) <<
213 std::hex << std::uppercase << std::setfill('0') <<
214 "F32 = 0x" << std::setw(8) << exp2_minus_21_f32 << ", " <<
215 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(exp2_minus_21_value) << ", " <<
216 "F16 = 0x" << std::setw(4) << exp2_minus_21_f16;
217
218 float exp2_minus_22_value;
219 memcpy(&exp2_minus_22_value, &exp2_minus_22_f32, sizeof(exp2_minus_22_value));
220 EXPECT_EQ(exp2_minus_22_f16, fp16_alt_from_fp32_value(exp2_minus_22_value)) <<
221 std::hex << std::uppercase << std::setfill('0') <<
222 "F32 = 0x" << std::setw(8) << exp2_minus_22_f32 << ", " <<
223 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(exp2_minus_22_value) << ", " <<
224 "F16 = 0x" << std::setw(4) << exp2_minus_22_f16;
225
226 float exp2_minus_23_value;
227 memcpy(&exp2_minus_23_value, &exp2_minus_23_f32, sizeof(exp2_minus_23_value));
228 EXPECT_EQ(exp2_minus_23_f16, fp16_alt_from_fp32_value(exp2_minus_23_value)) <<
229 std::hex << std::uppercase << std::setfill('0') <<
230 "F32 = 0x" << std::setw(8) << exp2_minus_23_f32 << ", " <<
231 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(exp2_minus_23_value) << ", " <<
232 "F16 = 0x" << std::setw(4) << exp2_minus_23_f16;
233
234 float exp2_minus_24_value;
235 memcpy(&exp2_minus_24_value, &exp2_minus_24_f32, sizeof(exp2_minus_24_value));
236 EXPECT_EQ(exp2_minus_24_f16, fp16_alt_from_fp32_value(exp2_minus_24_value)) <<
237 std::hex << std::uppercase << std::setfill('0') <<
238 "F32 = 0x" << std::setw(8) << exp2_minus_24_f32 << ", " <<
239 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(exp2_minus_24_value) << ", " <<
240 "F16 = 0x" << std::setw(4) << exp2_minus_24_f16;
241
242 float exp2_minus_25_value;
243 memcpy(&exp2_minus_25_value, &exp2_minus_25_f32, sizeof(exp2_minus_25_value));
244 EXPECT_EQ(exp2_minus_25_f16, fp16_alt_from_fp32_value(exp2_minus_25_value)) <<
245 std::hex << std::uppercase << std::setfill('0') <<
246 "F32 = 0x" << std::setw(8) << exp2_minus_25_f32 << ", " <<
247 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(exp2_minus_25_value) << ", " <<
248 "F16 = 0x" << std::setw(4) << exp2_minus_25_f16;
249}
250
251TEST(FP16_ALT_FROM_FP32_VALUE, zero) {
252 const uint16_t positive_zero_f16 = UINT16_C(0x0000);
253 const uint16_t negative_zero_f16 = UINT16_C(0x8000);
254
255 const uint32_t positive_zero_f32 = UINT32_C(0x00000000);
256 const uint32_t negative_zero_f32 = UINT32_C(0x80000000);
257
258 float positive_zero_value;
259 memcpy(&positive_zero_value, &positive_zero_f32, sizeof(positive_zero_value));
260 EXPECT_EQ(positive_zero_f16, fp16_alt_from_fp32_value(positive_zero_value)) <<
261 std::hex << std::uppercase << std::setfill('0') <<
262 "F32 = 0x" << std::setw(8) << positive_zero_f32 << ", " <<
263 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(positive_zero_value) << ", " <<
264 "F16 = 0x" << std::setw(4) << positive_zero_f16;
265
266 float negative_zero_value;
267 memcpy(&negative_zero_value, &negative_zero_f32, sizeof(negative_zero_value));
268 EXPECT_EQ(negative_zero_f16, fp16_alt_from_fp32_value(negative_zero_value)) <<
269 std::hex << std::uppercase << std::setfill('0') <<
270 "F32 = 0x" << std::setw(8) << negative_zero_f32 << ", " <<
271 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(negative_zero_value) << ", " <<
272 "F16 = 0x" << std::setw(4) << negative_zero_f16;
273}
274
275TEST(FP16_ALT_FROM_FP32_VALUE, infinity) {
276 const uint16_t max_f16 = UINT16_C(0x7FFF);
277 const uint16_t min_f16 = UINT16_C(0xFFFF);
278
279 const uint32_t positive_infinity_f32 = UINT32_C(0x7F800000);
280 const uint32_t negative_infinity_f32 = UINT32_C(0xFF800000);
281
282 float positive_infinity_value;
283 memcpy(&positive_infinity_value, &positive_infinity_f32, sizeof(positive_infinity_value));
284 EXPECT_EQ(max_f16, fp16_alt_from_fp32_value(positive_infinity_value)) <<
285 std::hex << std::uppercase << std::setfill('0') <<
286 "F32 = 0x" << std::setw(8) << positive_infinity_f32 << ", " <<
287 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(positive_infinity_value) << ", " <<
288 "F16 = 0x" << std::setw(4) << max_f16;
289
290 float negative_infinity_value;
291 memcpy(&negative_infinity_value, &negative_infinity_f32, sizeof(negative_infinity_value));
292 EXPECT_EQ(min_f16, fp16_alt_from_fp32_value(negative_infinity_value)) <<
293 std::hex << std::uppercase << std::setfill('0') <<
294 "F32 = 0x" << std::setw(8) << negative_infinity_f32 << ", " <<
295 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(negative_infinity_value) << ", " <<
296 "F16 = 0x" << std::setw(4) << min_f16;
297}
298
299TEST(FP16_ALT_FROM_FP32_VALUE, positive_nan) {
300 for (uint32_t nan_f32 = UINT32_C(0x7FFFFFFF); nan_f32 > UINT32_C(0x7F800000); nan_f32--) {
301 float nan_value;
302 memcpy(&nan_value, &nan_f32, sizeof(nan_value));
303 const uint16_t nan_f16 = fp16_alt_from_fp32_value(nan_value);
304
305 /* Check sign */
306 ASSERT_EQ(nan_f16 & UINT16_C(0x8000), 0) <<
307 std::hex << std::uppercase << std::setfill('0') <<
308 "F32 = 0x" << std::setw(8) << nan_f32 << ", " <<
309 "F16(F32) = 0x" << std::setw(4) << nan_f16;
310
311 /* Check exponent */
312 ASSERT_EQ(nan_f16 & UINT16_C(0x7C00), UINT16_C(0x7C00)) <<
313 std::hex << std::uppercase << std::setfill('0') <<
314 "F32 = 0x" << std::setw(8) << nan_f32 << ", " <<
315 "F16(F32) = 0x" << std::setw(4) << nan_f16;
316
317 /* Check mantissa */
318 ASSERT_NE(nan_f16 & UINT16_C(0x03FF), 0) <<
319 std::hex << std::uppercase << std::setfill('0') <<
320 "F32 = 0x" << std::setw(8) << nan_f32 << ", " <<
321 "F16(F32) = 0x" << std::setw(4) << nan_f16;
322 }
323}
324
325TEST(FP16_ALT_FROM_FP32_VALUE, negative_nan) {
326 for (uint32_t nan_f32 = UINT32_C(0xFFFFFFFF); nan_f32 > UINT32_C(0xFF800000); nan_f32--) {
327 float nan_value;
328 memcpy(&nan_value, &nan_f32, sizeof(nan_value));
329 const uint16_t nan_f16 = fp16_alt_from_fp32_value(nan_value);
330
331 /* Check sign */
332 ASSERT_EQ(nan_f16 & UINT16_C(0x8000), UINT16_C(0x8000)) <<
333 std::hex << std::uppercase << std::setfill('0') <<
334 "F32 = 0x" << std::setw(8) << nan_f32 << ", " <<
335 "F16(F32) = 0x" << std::setw(4) << nan_f16;
336
337 /* Check exponent */
338 ASSERT_EQ(nan_f16 & UINT16_C(0x7C00), UINT16_C(0x7C00)) <<
339 std::hex << std::uppercase << std::setfill('0') <<
340 "F32 = 0x" << std::setw(8) << nan_f32 << ", " <<
341 "F16(F32) = 0x" << std::setw(4) << nan_f16;
342
343 /* Check mantissa */
344 ASSERT_NE(nan_f16 & UINT16_C(0x03FF), 0) <<
345 std::hex << std::uppercase << std::setfill('0') <<
346 "F32 = 0x" << std::setw(8) << nan_f32 << ", " <<
347 "F16(F32) = 0x" << std::setw(4) << nan_f16;
348 }
349}
350
351TEST(FP16_ALT_FROM_FP32_VALUE, revertible) {
352 /* Positive values */
353 for (uint16_t f16 = UINT16_C(0x0000); f16 <= UINT16_C(0x7FFF); f16++) {
354 const float value_f32 = fp16_alt_to_fp32_value(f16);
355 uint32_t bits_f32;
356 memcpy(&bits_f32, &value_f32, sizeof(bits_f32));
357
358 ASSERT_EQ(f16, fp16_alt_from_fp32_value(value_f32)) <<
359 std::hex << std::uppercase << std::setfill('0') <<
360 "F16 = 0x" << std::setw(4) << f16 << ", " <<
361 "F32(F16) = 0x" << std::setw(8) << bits_f32 << ", " <<
362 "F16(F32(F16)) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(value_f32);
363 }
364
365 /* Negative values */
366 for (uint16_t f16 = UINT16_C(0xFFFF); f16 >= UINT16_C(0x8000); f16--) {
367 const float value_f32 = fp16_alt_to_fp32_value(f16);
368 uint32_t bits_f32;
369 memcpy(&bits_f32, &value_f32, sizeof(bits_f32));
370
371 ASSERT_EQ(f16, fp16_alt_from_fp32_value(value_f32)) <<
372 std::hex << std::uppercase << std::setfill('0') <<
373 "F16 = 0x" << std::setw(4) << f16 << ", " <<
374 "F32(F16) = 0x" << std::setw(8) << bits_f32 << ", " <<
375 "F16(F32(F16)) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(value_f32);
376 }
377}
378
379TEST(FP16_ALT_FROM_FP32_VALUE, underflow) {
380 const uint32_t min_nonzero_f32 = UINT32_C(0x33000001);
381 const uint16_t zero_f16 = UINT16_C(0x0000);
382 const uint16_t min_f16 = UINT16_C(0x0001);
383 for (uint32_t bits = UINT32_C(0x00000001); bits < min_nonzero_f32; bits++) {
384 float value;
385 memcpy(&value, &bits, sizeof(value));
386 ASSERT_EQ(zero_f16, fp16_alt_from_fp32_value(value)) <<
387 std::hex << std::uppercase << std::setfill('0') <<
388 "F32 = 0x" << std::setw(8) << bits << ", " <<
389 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(value) << ", " <<
390 "F16 = 0x" << std::setw(4) << zero_f16;
391 }
392 float min_nonzero_value;
393 memcpy(&min_nonzero_value, &min_nonzero_f32, sizeof(min_nonzero_value));
394 ASSERT_EQ(min_f16, fp16_alt_from_fp32_value(min_nonzero_value)) <<
395 std::hex << std::uppercase << std::setfill('0') <<
396 "F32 = 0x" << std::setw(8) << min_nonzero_f32 << ", " <<
397 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(min_nonzero_value) << ", " <<
398 "F16 = 0x" << std::setw(4) << min_f16;
399}
400
401TEST(FP16_ALT_FROM_FP32_VALUE, saturation) {
402 const uint32_t max_f16_f32 = UINT32_C(0x47FFE000);
403 const uint16_t max_f16 = UINT16_C(0x7FFF);
404 const uint32_t positive_infinity_f32 = UINT32_C(0x7F800000);
405 for (uint32_t bits = positive_infinity_f32; bits > max_f16_f32; bits--) {
406 float value;
407 memcpy(&value, &bits, sizeof(value));
408 ASSERT_EQ(max_f16, fp16_alt_from_fp32_value(value)) <<
409 std::hex << std::uppercase << std::setfill('0') <<
410 "F32 = 0x" << std::setw(8) << bits << ", " <<
411 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(value) << ", " <<
412 "F16 = 0x" << std::setw(4) << max_f16;
413 }
414}
415
416TEST(FP16_ALT_FROM_FP32_VALUE, positive_denormalized_values) {
417 const uint32_t min_nonzero_f32 = UINT32_C(0x33000001);
418
419 uint32_t f32_begin = min_nonzero_f32;
420 for (uint16_t f16 = 0; f16 < UINT16_C(0x0400); f16++) {
421 const uint32_t f32_end = fp16::denormalizedRanges[f16];
422 for (uint32_t f32 = f32_begin; f32 < f32_end; f32++) {
423 float value;
424 memcpy(&value, &f32, sizeof(value));
425 ASSERT_EQ(f16, fp16_alt_from_fp32_value(value)) <<
426 std::hex << std::uppercase << std::setfill('0') <<
427 "F32 = 0x" << std::setw(8) << f32 << ", " <<
428 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(value) << ", " <<
429 "F16 = 0x" << std::setw(4) << f16;
430 }
431 f32_begin = f32_end;
432 }
433}
434
435TEST(FP16_ALT_FROM_FP32_VALUE, negative_denormalized_values) {
436 const uint32_t min_nonzero_f32 = UINT32_C(0x33000001);
437
438 uint32_t f32_begin = min_nonzero_f32 | UINT32_C(0x80000000);
439 for (uint16_t f16 = UINT16_C(0x8000); f16 < UINT16_C(0x8400); f16++) {
440 const uint32_t f32_end = fp16::denormalizedRanges[f16 & UINT16_C(0x7FFF)] | UINT32_C(0x80000000);
441 for (uint32_t f32 = f32_begin; f32 < f32_end; f32++) {
442 float value;
443 memcpy(&value, &f32, sizeof(value));
444 ASSERT_EQ(f16, fp16_alt_from_fp32_value(value)) <<
445 std::hex << std::uppercase << std::setfill('0') <<
446 "F32 = 0x" << std::setw(8) << f32 << ", " <<
447 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(value) << ", " <<
448 "F16 = 0x" << std::setw(4) << f16;
449 }
450 f32_begin = f32_end;
451 }
452}
453
454TEST(FP16_ALT_FROM_FP32_VALUE, positive_normalized_values) {
455 /* Minimum number that rounds to 1.0h when converted to half-precision */
456 const uint32_t min_one_f32 = UINT32_C(0x3F7FF000);
457 const uint32_t e_bias = 15;
458
459 for (int32_t e = -14; e <= 16; e++) {
460 uint32_t f32_begin = min_one_f32 + (uint32_t(e) << 23);
461 for (uint16_t f16 = uint16_t(e + e_bias) << 10; f16 < uint16_t(e + e_bias + 1) << 10; f16++) {
462 const uint32_t f32_end = fp16::normalizedRanges[f16 & UINT16_C(0x3FF)] + (uint32_t(e) << 23);
463 for (uint32_t f32 = f32_begin; f32 < f32_end; f32++) {
464 float value;
465 memcpy(&value, &f32, sizeof(value));
466 ASSERT_EQ(f16, fp16_alt_from_fp32_value(value)) <<
467 std::hex << std::uppercase << std::setfill('0') <<
468 "F32 = 0x" << std::setw(8) << f32 << ", " <<
469 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(value) << ", " <<
470 "F16 = 0x" << std::setw(4) << f16;
471 }
472 f32_begin = f32_end;
473 }
474 }
475}
476
477TEST(FP16_ALT_FROM_FP32_VALUE, negative_normalized_values) {
478 /* Minimum number that rounds to 1.0h when converted to half-precision */
479 const uint32_t min_one_f32 = UINT32_C(0x3F7FF000);
480 const uint32_t e_bias = 15;
481
482 for (int32_t e = -14; e <= 16; e++) {
483 uint32_t f32_begin = (min_one_f32 | UINT32_C(0x80000000)) + (uint32_t(e) << 23);
484 for (uint16_t f16 = (UINT16_C(0x8000) | (uint16_t(e + e_bias) << 10)); f16 < (UINT16_C(0x8000) | (uint16_t(e + e_bias + 1) << 10)); f16++) {
485 const uint32_t f32_end = (fp16::normalizedRanges[f16 & UINT16_C(0x3FF)] | UINT32_C(0x80000000)) + (uint32_t(e) << 23);
486 for (uint32_t f32 = f32_begin; f32 < f32_end; f32++) {
487 float value;
488 memcpy(&value, &f32, sizeof(value));
489 ASSERT_EQ(f16, fp16_alt_from_fp32_value(value)) <<
490 std::hex << std::uppercase << std::setfill('0') <<
491 "F32 = 0x" << std::setw(8) << f32 << ", " <<
492 "F16(F32) = 0x" << std::setw(4) << fp16_alt_from_fp32_value(value) << ", " <<
493 "F16 = 0x" << std::setw(4) << f16;
494 }
495 f32_begin = f32_end;
496 }
497 }
498}