]> git.sesse.net Git - movit/blob - fp16_test.cpp
Fix broken YCbCr subpixel positioning. Caught by the unit tests.
[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         // Ignore the sign bit.
45         EXPECT_EQ(0x7e00, fp64_to_fp16(0.0 / 0.0) & 0x7fff);
46         EXPECT_TRUE(isnan(fp16_to_fp64(0xfe00)));
47
48         fp64 borderline_inf;
49         borderline_inf.ll = 0x7ff0000000000000ull;
50         fp64 borderline_nan;
51         borderline_nan.ll = 0x7ff0000000000001ull;
52
53         ASSERT_FALSE(isfinite(borderline_inf.f));
54         ASSERT_FALSE(isnan(borderline_inf.f));
55
56         ASSERT_FALSE(isfinite(borderline_nan.f));
57         ASSERT_TRUE(isnan(borderline_nan.f));
58
59         double borderline_inf_roundtrip = fp16_to_fp64(fp64_to_fp16(borderline_inf.f));
60         double borderline_nan_roundtrip = fp16_to_fp64(fp64_to_fp16(borderline_nan.f));
61
62         EXPECT_FALSE(isfinite(borderline_inf_roundtrip));
63         EXPECT_FALSE(isnan(borderline_inf_roundtrip));
64
65         EXPECT_FALSE(isfinite(borderline_nan_roundtrip));
66         EXPECT_TRUE(isnan(borderline_nan_roundtrip));
67 }
68
69 TEST(FP16Test, Denormals) {
70         const double smallest_fp16_denormal = 5.9604644775390625e-08;
71         EXPECT_EQ(0x0001, fp64_to_fp16(smallest_fp16_denormal));
72         EXPECT_EQ(0x0000, fp64_to_fp16(0.5 * smallest_fp16_denormal));  // Round-to-even.
73         EXPECT_EQ(0x0001, fp64_to_fp16(0.51 * smallest_fp16_denormal));
74         EXPECT_EQ(0x0002, fp64_to_fp16(1.5 * smallest_fp16_denormal));
75
76         const double smallest_fp16_non_denormal = 6.103515625e-05;
77         EXPECT_EQ(0x0400, fp64_to_fp16(smallest_fp16_non_denormal));
78         EXPECT_EQ(0x0400, fp64_to_fp16(smallest_fp16_non_denormal - 0.5 * smallest_fp16_denormal));  // Round-to-even.
79         EXPECT_EQ(0x03ff, fp64_to_fp16(smallest_fp16_non_denormal - smallest_fp16_denormal));
80 }
81
82 // Randomly test a large number of fp64 -> fp32 conversions, comparing
83 // against the FPU.
84 TEST(FP16Test, FP32ReferenceDownconvert) {
85         srand(12345);
86
87         for (int i = 0; i < 1000000; ++i) {
88                 unsigned r1 = rand();
89                 unsigned r2 = rand();
90                 unsigned r3 = rand();
91                 union fp64 src;
92                 union fp32 reference, result;
93
94                 src.ll = (((unsigned long long)r1) << 33) ^ ((unsigned long long)r2 << 16) ^ r3;
95                 reference.f = float(src.f);
96                 result.u = fp64_to_fp32(src.f);
97
98                 EXPECT_EQ(isnan(result.f), isnan(reference.f));
99                 if (!isnan(result.f)) {
100                         EXPECT_EQ(result.u, reference.u)
101                             << src.f << " got rounded to " << result.u << " (" << result.f << ")";
102                 }
103         }
104 }
105
106 // Randomly test a large number of fp32 -> fp64 conversions, comparing
107 // against the FPU.
108 TEST(FP16Test, FP32ReferenceUpconvert) {
109         srand(12345);
110
111         for (int i = 0; i < 1000000; ++i) {
112                 unsigned r1 = rand();
113                 unsigned r2 = rand();
114                 union fp32 src;
115                 union fp64 reference, result;
116
117                 src.u = ((unsigned long long)r1 << 16) ^ r2;
118                 reference.f = double(src.f);
119                 result.f = fp32_to_fp64(src.u);
120
121                 EXPECT_EQ(isnan(result.f), isnan(reference.f));
122                 if (!isnan(result.f)) {
123                         EXPECT_EQ(result.ll, reference.ll)
124                             << src.f << " got converted to " << result.ll << " (" << result.f << ")";
125                 }
126         }
127 }
128
129 }  // namespace movit