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