1 /*
2 * Copyright 2023 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/private/base/SkAssert.h"
9 #include "include/private/base/SkFloatingPoint.h"
10 #include "src/base/SkUtils.h"
11 #include "tests/Test.h"
12
13 #include <array>
14 #include <cfloat>
15 #include <cmath>
16 #include <cstdint>
17 #include <cstring>
18 #include <limits>
19
DEF_TEST(DoubleNearlyZero,reporter)20 DEF_TEST(DoubleNearlyZero, reporter) {
21 REPORTER_ASSERT(reporter, sk_double_nearly_zero(0.));
22 REPORTER_ASSERT(reporter, sk_double_nearly_zero(-0.));
23 REPORTER_ASSERT(reporter, sk_double_nearly_zero(DBL_EPSILON));
24 REPORTER_ASSERT(reporter, sk_double_nearly_zero(-DBL_EPSILON));
25
26 double nearly = 1. / 20000000000LL;
27 REPORTER_ASSERT(reporter, nearly != 0);
28 REPORTER_ASSERT(reporter, sk_double_nearly_zero(nearly));
29 REPORTER_ASSERT(reporter, sk_double_nearly_zero(-nearly));
30
31 REPORTER_ASSERT(reporter, !sk_double_nearly_zero(FLT_EPSILON));
32 REPORTER_ASSERT(reporter, !sk_double_nearly_zero(-FLT_EPSILON));
33 REPORTER_ASSERT(reporter, !sk_double_nearly_zero(1));
34 REPORTER_ASSERT(reporter, !sk_double_nearly_zero(-1));
35 REPORTER_ASSERT(reporter, !sk_double_nearly_zero(INFINITY));
36 REPORTER_ASSERT(reporter, !sk_double_nearly_zero(HUGE_VALF));
37 REPORTER_ASSERT(reporter, !sk_double_nearly_zero(HUGE_VAL));
38 REPORTER_ASSERT(reporter, !sk_double_nearly_zero(HUGE_VALL));
39 REPORTER_ASSERT(reporter, !sk_double_nearly_zero(-INFINITY));
40 REPORTER_ASSERT(reporter, !sk_double_nearly_zero(-HUGE_VALF));
41 REPORTER_ASSERT(reporter, !sk_double_nearly_zero(-HUGE_VAL));
42 REPORTER_ASSERT(reporter, !sk_double_nearly_zero(-HUGE_VALL));
43 REPORTER_ASSERT(reporter, !sk_double_nearly_zero(NAN));
44 REPORTER_ASSERT(reporter, !sk_double_nearly_zero(-NAN));
45 }
46
DEF_TEST(DoubleNearlyEqualUlps,reporter)47 DEF_TEST(DoubleNearlyEqualUlps, reporter) {
48 // Our tolerance is looser than DBL_EPSILON
49 REPORTER_ASSERT(reporter, sk_doubles_nearly_equal_ulps(1., 1.));
50 REPORTER_ASSERT(reporter, sk_doubles_nearly_equal_ulps(1., 1. - DBL_EPSILON));
51 REPORTER_ASSERT(reporter, sk_doubles_nearly_equal_ulps(1., 1. + DBL_EPSILON));
52 REPORTER_ASSERT(reporter, sk_doubles_nearly_equal_ulps(100.5, 100.5));
53 REPORTER_ASSERT(reporter, sk_doubles_nearly_equal_ulps(100.5, 100.5 - DBL_EPSILON));
54 REPORTER_ASSERT(reporter, sk_doubles_nearly_equal_ulps(100.5, 100.5 + DBL_EPSILON));
55
56 // Our tolerance is tighter than FLT_EPSILON
57 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(1., 1. - FLT_EPSILON));
58 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(1., 1. + FLT_EPSILON));
59 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(100.5, 100.5 - FLT_EPSILON));
60 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(100.5, 100.5 + FLT_EPSILON));
61 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(0, 0.1));
62 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(FLT_EPSILON, 0));
63
64 REPORTER_ASSERT(reporter, sk_doubles_nearly_equal_ulps(INFINITY, INFINITY));
65 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(INFINITY, 10));
66 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(10, INFINITY));
67 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(NAN, INFINITY));
68
69 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(INFINITY, -INFINITY));
70 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(-INFINITY, INFINITY));
71 REPORTER_ASSERT(reporter, sk_doubles_nearly_equal_ulps(-INFINITY, -INFINITY));
72
73 // Test values upto the edge of infinity.
74 const double biggest = std::numeric_limits<double>::max();
75 auto almostBiggest = [&](int n) {
76 double almostBiggest = biggest;
77 for (int i = 0; i < n; ++i) {
78 almostBiggest = std::nextafter(almostBiggest, -INFINITY);
79 }
80 return almostBiggest;
81 };
82 const double nextBiggest = almostBiggest(1);
83 REPORTER_ASSERT(reporter, sk_doubles_nearly_equal_ulps(biggest, nextBiggest));
84 REPORTER_ASSERT(reporter, sk_doubles_nearly_equal_ulps(biggest, almostBiggest(16)));
85 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(biggest, almostBiggest(17)));
86
87 // One ulp less would be infinity.
88 const uint64_t smallestNANPattern =
89 0b0'11111111111'0000000000000000000000000000000000000000000000000001;
90 double smallestNAN;
91 memcpy(&smallestNAN, &smallestNANPattern, sizeof(double));
92 SkASSERT(std::isnan(smallestNAN));
93 SkASSERT(biggest != nextBiggest);
94
95 // Sanity check.
96 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(smallestNAN, NAN));
97
98 // Make sure to return false along the edge of infinity.
99 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(INFINITY, biggest));
100 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(smallestNAN, biggest));
101 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(smallestNAN, INFINITY));
102
103 const double smallest = std::numeric_limits<double>::denorm_min();
104 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(NAN, NAN));
105 REPORTER_ASSERT(reporter, sk_doubles_nearly_equal_ulps(smallest, 0));
106 REPORTER_ASSERT(reporter, sk_doubles_nearly_equal_ulps(smallest, -smallest));
107 REPORTER_ASSERT(reporter, sk_doubles_nearly_equal_ulps(8*smallest, -8*smallest));
108 REPORTER_ASSERT(reporter, !sk_doubles_nearly_equal_ulps(8*smallest, -9*smallest));
109 }
110
DEF_TEST(BitCastDoubleRoundTrip,reporter)111 DEF_TEST(BitCastDoubleRoundTrip, reporter) {
112 std::array<double, 5> testCases = {0.0, 1.0, -13.0, 1.234567890123456, -543210.987654321};
113
114 for (size_t i = 0; i < testCases.size(); i++) {
115 double input = testCases[i];
116 uint64_t bits = sk_bit_cast<uint64_t>(input);
117 double output = sk_bit_cast<double>(bits);
118 REPORTER_ASSERT(reporter, input == output, "%.16f is not exactly %.16f", input, output);
119 }
120
121 {
122 uint64_t bits = sk_bit_cast<uint64_t>((double) NAN);
123 double output = sk_bit_cast<double>(bits);
124 REPORTER_ASSERT(reporter, std::isnan(output), "%.16f is not nan", output);
125 }
126 {
127 uint64_t bits = sk_bit_cast<uint64_t>((double) INFINITY);
128 double output = sk_bit_cast<double>(bits);
129 REPORTER_ASSERT(reporter, !SkIsFinite(output), "%.16f is not infinity", output);
130 }
131 }
132
DEF_TEST(FMA,reporter)133 DEF_TEST(FMA, reporter) {
134 // 0b0'01111111111'00'0000000000'0000000000'0000000010'0000000000'0000000000
135 double over1 = 1+4.656612873e-10;
136
137 // 0b0'01111111110'11'1111111111'1111111111'1111111100'0000000000'0000000000
138 double under1 = 1-4.656612873e-10;
139
140 // Precision loss
141 // -------------- becomes 1; extra bits are rounded off.
142 double x = std::fma(1, -1, over1 * under1);
143
144 // Precision maintained
145 // ------------- becomes 1 - 2^-62; extra bits are maintained
146 double y = std::fma(over1, under1, -1);
147
148 REPORTER_ASSERT(reporter, x == 0);
149 REPORTER_ASSERT(reporter, y == -exp2(-62));
150 }
151
DEF_TEST(Midpoint,reporter)152 DEF_TEST(Midpoint, reporter) {
153 const float smallest = std::numeric_limits<float>::denorm_min();
154 REPORTER_ASSERT(reporter, sk_float_midpoint(smallest, smallest) == smallest);
155 REPORTER_ASSERT(reporter, sk_float_midpoint(smallest, -smallest) == 0);
156
157 const float biggest = std::numeric_limits<float>::max();
158 REPORTER_ASSERT(reporter, sk_float_midpoint(biggest, biggest) == biggest);
159 REPORTER_ASSERT(reporter, sk_float_midpoint(biggest, -biggest) == 0);
160
161 }
162