]> git.sesse.net Git - movit/blob - fp16_test.cpp
Add a temporary variable to reduce the amount of tedious typing.
[movit] / fp16_test.cpp
1 #include "fp16.h"
2
3 #include <math.h>
4 #include <gtest/gtest.h>
5
6 namespace movit {
7
8 TEST(FP16Test, Simple) {
9         EXPECT_EQ(0x0000, fp64_to_fp16(0.0));
10         EXPECT_DOUBLE_EQ(0.0, fp16_to_fp64(0x0000));
11
12         EXPECT_EQ(0x3c00, fp64_to_fp16(1.0));
13         EXPECT_DOUBLE_EQ(1.0, fp16_to_fp64(0x3c00));
14
15         EXPECT_EQ(0x3555, fp64_to_fp16(1.0 / 3.0));
16         EXPECT_DOUBLE_EQ(0.333251953125, fp16_to_fp64(0x3555));
17 }
18
19 TEST(FP16Test, RoundToNearestEven) {
20         ASSERT_DOUBLE_EQ(1.0, fp16_to_fp64(0x3c00));
21
22         double x0 = fp16_to_fp64(0x3c00);
23         double x1 = fp16_to_fp64(0x3c01);
24         double x2 = fp16_to_fp64(0x3c02);
25         double x3 = fp16_to_fp64(0x3c03);
26         double x4 = fp16_to_fp64(0x3c04);
27
28         EXPECT_EQ(0x3c00, fp64_to_fp16(0.5 * (x0 + x1)));
29         EXPECT_EQ(0x3c02, fp64_to_fp16(0.5 * (x1 + x2)));
30         EXPECT_EQ(0x3c02, fp64_to_fp16(0.5 * (x2 + x3)));
31         EXPECT_EQ(0x3c04, fp64_to_fp16(0.5 * (x3 + x4)));
32 }
33
34 union fp64 {
35         double f;
36         unsigned long long ll;
37 };
38 union fp32 {
39         float f;
40         unsigned int u;
41 };
42
43 TEST(FP16Test, NaN) {
44         EXPECT_EQ(0xfe00, fp64_to_fp16(0.0 / 0.0));
45         EXPECT_TRUE(isnan(fp16_to_fp64(0xfe00)));
46
47         fp64 borderline_inf;
48         borderline_inf.ll = 0x7ff0000000000000ull;
49         fp64 borderline_nan;
50         borderline_nan.ll = 0x7ff0000000000001ull;
51
52         ASSERT_FALSE(isfinite(borderline_inf.f));
53         ASSERT_FALSE(isnan(borderline_inf.f));
54
55         ASSERT_FALSE(isfinite(borderline_nan.f));
56         ASSERT_TRUE(isnan(borderline_nan.f));
57
58         double borderline_inf_roundtrip = fp16_to_fp64(fp64_to_fp16(borderline_inf.f));
59         double borderline_nan_roundtrip = fp16_to_fp64(fp64_to_fp16(borderline_nan.f));
60
61         EXPECT_FALSE(isfinite(borderline_inf_roundtrip));
62         EXPECT_FALSE(isnan(borderline_inf_roundtrip));
63
64         EXPECT_FALSE(isfinite(borderline_nan_roundtrip));
65         EXPECT_TRUE(isnan(borderline_nan_roundtrip));
66 }
67
68 TEST(FP16Test, Denormals) {
69         const double smallest_fp16_denormal = 5.9604644775390625e-08;
70         EXPECT_EQ(0x0001, fp64_to_fp16(smallest_fp16_denormal));
71         EXPECT_EQ(0x0000, fp64_to_fp16(0.5 * smallest_fp16_denormal));  // Round-to-even.
72         EXPECT_EQ(0x0001, fp64_to_fp16(0.51 * smallest_fp16_denormal));
73         EXPECT_EQ(0x0002, fp64_to_fp16(1.5 * smallest_fp16_denormal));
74
75         const double smallest_fp16_non_denormal = 6.103515625e-05;
76         EXPECT_EQ(0x0400, fp64_to_fp16(smallest_fp16_non_denormal));
77         EXPECT_EQ(0x0400, fp64_to_fp16(smallest_fp16_non_denormal - 0.5 * smallest_fp16_denormal));  // Round-to-even.
78         EXPECT_EQ(0x03ff, fp64_to_fp16(smallest_fp16_non_denormal - smallest_fp16_denormal));
79 }
80
81 // Randomly test a large number of fp64 -> fp32 conversions, comparing
82 // against the FPU.
83 TEST(FP16Test, FP32ReferenceDownconvert) {
84         srand(12345);
85
86         for (int i = 0; i < 1000000; ++i) {
87                 unsigned r1 = rand();
88                 unsigned r2 = rand();
89                 unsigned r3 = rand();
90                 union fp64 src;
91                 union fp32 reference, result;
92
93                 src.ll = (((unsigned long long)r1) << 33) ^ ((unsigned long long)r2 << 16) ^ r3;
94                 reference.f = float(src.f);
95                 result.u = fp64_to_fp32(src.f);
96
97                 EXPECT_EQ(isnan(result.f), isnan(reference.f));
98                 if (!isnan(result.f)) {
99                         EXPECT_EQ(result.u, reference.u)
100                             << src.f << " got rounded to " << result.u << " (" << result.f << ")";
101                 }
102         }
103 }
104
105 // Randomly test a large number of fp32 -> fp64 conversions, comparing
106 // against the FPU.
107 TEST(FP16Test, FP32ReferenceUpconvert) {
108         srand(12345);
109
110         for (int i = 0; i < 1000000; ++i) {
111                 unsigned r1 = rand();
112                 unsigned r2 = rand();
113                 union fp32 src;
114                 union fp64 reference, result;
115
116                 src.u = ((unsigned long long)r1 << 16) ^ r2;
117                 reference.f = double(src.f);
118                 result.f = fp32_to_fp64(src.u);
119
120                 EXPECT_EQ(isnan(result.f), isnan(reference.f));
121                 if (!isnan(result.f)) {
122                         EXPECT_EQ(result.ll, reference.ll)
123                             << src.f << " got converted to " << result.ll << " (" << result.f << ")";
124                 }
125         }
126 }
127
128 }  // namespace movit