1 #include "fp16.h"
2 
3 #include <cmath>
4 #include <gtest/gtest.h>
5 
6 namespace movit {
7 namespace {
8 
make_fp16(unsigned short x)9 fp16_int_t make_fp16(unsigned short x)
10 {
11 	fp16_int_t ret;
12 	ret.val = x;
13 	return ret;
14 }
15 
16 }  // namespace
17 
TEST(FP16Test,Simple)18 TEST(FP16Test, Simple) {
19 	EXPECT_EQ(0x0000, fp32_to_fp16(0.0).val);
20 	EXPECT_DOUBLE_EQ(0.0, fp16_to_fp32(make_fp16(0x0000)));
21 
22 	EXPECT_EQ(0x3c00, fp32_to_fp16(1.0).val);
23 	EXPECT_DOUBLE_EQ(1.0, fp16_to_fp32(make_fp16(0x3c00)));
24 
25 	EXPECT_EQ(0x3555, fp32_to_fp16(1.0 / 3.0).val);
26 	EXPECT_DOUBLE_EQ(0.333251953125, fp16_to_fp32(make_fp16(0x3555)));
27 }
28 
TEST(FP16Test,RoundToNearestEven)29 TEST(FP16Test, RoundToNearestEven) {
30 	ASSERT_DOUBLE_EQ(1.0, fp16_to_fp32(make_fp16(0x3c00)));
31 
32 	double x0 = fp16_to_fp32(make_fp16(0x3c00));
33 	double x1 = fp16_to_fp32(make_fp16(0x3c01));
34 	double x2 = fp16_to_fp32(make_fp16(0x3c02));
35 	double x3 = fp16_to_fp32(make_fp16(0x3c03));
36 	double x4 = fp16_to_fp32(make_fp16(0x3c04));
37 
38 	EXPECT_EQ(0x3c00, fp32_to_fp16(0.5 * (x0 + x1)).val);
39 	EXPECT_EQ(0x3c02, fp32_to_fp16(0.5 * (x1 + x2)).val);
40 	EXPECT_EQ(0x3c02, fp32_to_fp16(0.5 * (x2 + x3)).val);
41 	EXPECT_EQ(0x3c04, fp32_to_fp16(0.5 * (x3 + x4)).val);
42 }
43 
44 union fp64 {
45 	double f;
46 	unsigned long long ll;
47 };
48 
49 #ifdef __F16C__
50 union fp32 {
51 	float f;
52 	unsigned int u;
53 };
54 #endif
55 
TEST(FP16Test,NaN)56 TEST(FP16Test, NaN) {
57 	// Ignore the sign bit.
58 	EXPECT_EQ(0x7e00, fp32_to_fp16(0.0 / 0.0).val & 0x7fff);
59 	EXPECT_TRUE(std::isnan(fp16_to_fp32(make_fp16(0xfe00))));
60 
61 	fp32 borderline_inf;
62 	borderline_inf.u = 0x7f800000ull;
63 	fp32 borderline_nan;
64 	borderline_nan.u = 0x7f800001ull;
65 
66 	ASSERT_FALSE(std::isfinite(borderline_inf.f));
67 	ASSERT_FALSE(std::isnan(borderline_inf.f));
68 
69 	ASSERT_FALSE(std::isfinite(borderline_nan.f));
70 	ASSERT_TRUE(std::isnan(borderline_nan.f));
71 
72 	double borderline_inf_roundtrip = fp16_to_fp32(fp32_to_fp16(borderline_inf.f));
73 	double borderline_nan_roundtrip = fp16_to_fp32(fp32_to_fp16(borderline_nan.f));
74 
75 	EXPECT_FALSE(std::isfinite(borderline_inf_roundtrip));
76 	EXPECT_FALSE(std::isnan(borderline_inf_roundtrip));
77 
78 	EXPECT_FALSE(std::isfinite(borderline_nan_roundtrip));
79 	EXPECT_TRUE(std::isnan(borderline_nan_roundtrip));
80 }
81 
TEST(FP16Test,Denormals)82 TEST(FP16Test, Denormals) {
83 	const double smallest_fp16_denormal = 5.9604644775390625e-08;
84 	EXPECT_EQ(0x0001, fp32_to_fp16(smallest_fp16_denormal).val);
85 	EXPECT_EQ(0x0000, fp32_to_fp16(0.5 * smallest_fp16_denormal).val);  // Round-to-even.
86 	EXPECT_EQ(0x0001, fp32_to_fp16(0.51 * smallest_fp16_denormal).val);
87 	EXPECT_EQ(0x0002, fp32_to_fp16(1.5 * smallest_fp16_denormal).val);
88 
89 	const double smallest_fp16_non_denormal = 6.103515625e-05;
90 	EXPECT_EQ(0x0400, fp32_to_fp16(smallest_fp16_non_denormal).val);
91 	EXPECT_EQ(0x0400, fp32_to_fp16(smallest_fp16_non_denormal - 0.5 * smallest_fp16_denormal).val);  // Round-to-even.
92 	EXPECT_EQ(0x03ff, fp32_to_fp16(smallest_fp16_non_denormal - smallest_fp16_denormal).val);
93 }
94 
95 }  // namespace movit
96