1 /*
2 * Copyright 2012 Google Inc.
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 #include "SkFloatBits.h"
8 #include "SkPathOpsTypes.h"
9
arguments_denormalized(float a,float b,int epsilon)10 static bool arguments_denormalized(float a, float b, int epsilon) {
11 float denormalizedCheck = FLT_EPSILON * epsilon / 2;
12 return fabsf(a) <= denormalizedCheck && fabsf(b) <= denormalizedCheck;
13 }
14
15 // from http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
16 // FIXME: move to SkFloatBits.h
equal_ulps(float a,float b,int epsilon,int depsilon)17 static bool equal_ulps(float a, float b, int epsilon, int depsilon) {
18 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
19 return false;
20 }
21 if (arguments_denormalized(a, b, depsilon)) {
22 return true;
23 }
24 int aBits = SkFloatAs2sCompliment(a);
25 int bBits = SkFloatAs2sCompliment(b);
26 // Find the difference in ULPs.
27 return aBits < bBits + epsilon && bBits < aBits + epsilon;
28 }
29
d_equal_ulps(float a,float b,int epsilon)30 static bool d_equal_ulps(float a, float b, int epsilon) {
31 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
32 return false;
33 }
34 int aBits = SkFloatAs2sCompliment(a);
35 int bBits = SkFloatAs2sCompliment(b);
36 // Find the difference in ULPs.
37 return aBits < bBits + epsilon && bBits < aBits + epsilon;
38 }
39
not_equal_ulps(float a,float b,int epsilon)40 static bool not_equal_ulps(float a, float b, int epsilon) {
41 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
42 return false;
43 }
44 if (arguments_denormalized(a, b, epsilon)) {
45 return false;
46 }
47 int aBits = SkFloatAs2sCompliment(a);
48 int bBits = SkFloatAs2sCompliment(b);
49 // Find the difference in ULPs.
50 return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
51 }
52
d_not_equal_ulps(float a,float b,int epsilon)53 static bool d_not_equal_ulps(float a, float b, int epsilon) {
54 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
55 return false;
56 }
57 int aBits = SkFloatAs2sCompliment(a);
58 int bBits = SkFloatAs2sCompliment(b);
59 // Find the difference in ULPs.
60 return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
61 }
62
less_ulps(float a,float b,int epsilon)63 static bool less_ulps(float a, float b, int epsilon) {
64 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
65 return false;
66 }
67 if (arguments_denormalized(a, b, epsilon)) {
68 return a <= b - FLT_EPSILON * epsilon;
69 }
70 int aBits = SkFloatAs2sCompliment(a);
71 int bBits = SkFloatAs2sCompliment(b);
72 // Find the difference in ULPs.
73 return aBits <= bBits - epsilon;
74 }
75
less_or_equal_ulps(float a,float b,int epsilon)76 static bool less_or_equal_ulps(float a, float b, int epsilon) {
77 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
78 return false;
79 }
80 if (arguments_denormalized(a, b, epsilon)) {
81 return a < b + FLT_EPSILON * epsilon;
82 }
83 int aBits = SkFloatAs2sCompliment(a);
84 int bBits = SkFloatAs2sCompliment(b);
85 // Find the difference in ULPs.
86 return aBits < bBits + epsilon;
87 }
88
89 // equality using the same error term as between
AlmostBequalUlps(float a,float b)90 bool AlmostBequalUlps(float a, float b) {
91 const int UlpsEpsilon = 2;
92 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
93 }
94
AlmostPequalUlps(float a,float b)95 bool AlmostPequalUlps(float a, float b) {
96 const int UlpsEpsilon = 8;
97 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
98 }
99
AlmostDequalUlps(float a,float b)100 bool AlmostDequalUlps(float a, float b) {
101 const int UlpsEpsilon = 16;
102 return d_equal_ulps(a, b, UlpsEpsilon);
103 }
104
AlmostEqualUlps(float a,float b)105 bool AlmostEqualUlps(float a, float b) {
106 const int UlpsEpsilon = 16;
107 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
108 }
109
NotAlmostEqualUlps(float a,float b)110 bool NotAlmostEqualUlps(float a, float b) {
111 const int UlpsEpsilon = 16;
112 return not_equal_ulps(a, b, UlpsEpsilon);
113 }
114
NotAlmostDequalUlps(float a,float b)115 bool NotAlmostDequalUlps(float a, float b) {
116 const int UlpsEpsilon = 16;
117 return d_not_equal_ulps(a, b, UlpsEpsilon);
118 }
119
RoughlyEqualUlps(float a,float b)120 bool RoughlyEqualUlps(float a, float b) {
121 const int UlpsEpsilon = 256;
122 const int DUlpsEpsilon = 1024;
123 return equal_ulps(a, b, UlpsEpsilon, DUlpsEpsilon);
124 }
125
AlmostBetweenUlps(float a,float b,float c)126 bool AlmostBetweenUlps(float a, float b, float c) {
127 const int UlpsEpsilon = 2;
128 return a <= c ? less_or_equal_ulps(a, b, UlpsEpsilon) && less_or_equal_ulps(b, c, UlpsEpsilon)
129 : less_or_equal_ulps(b, a, UlpsEpsilon) && less_or_equal_ulps(c, b, UlpsEpsilon);
130 }
131
AlmostLessUlps(float a,float b)132 bool AlmostLessUlps(float a, float b) {
133 const int UlpsEpsilon = 16;
134 return less_ulps(a, b, UlpsEpsilon);
135 }
136
AlmostLessOrEqualUlps(float a,float b)137 bool AlmostLessOrEqualUlps(float a, float b) {
138 const int UlpsEpsilon = 16;
139 return less_or_equal_ulps(a, b, UlpsEpsilon);
140 }
141
UlpsDistance(float a,float b)142 int UlpsDistance(float a, float b) {
143 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
144 return SK_MaxS32;
145 }
146 SkFloatIntUnion floatIntA, floatIntB;
147 floatIntA.fFloat = a;
148 floatIntB.fFloat = b;
149 // Different signs means they do not match.
150 if ((floatIntA.fSignBitInt < 0) != (floatIntB.fSignBitInt < 0)) {
151 // Check for equality to make sure +0 == -0
152 return a == b ? 0 : SK_MaxS32;
153 }
154 // Find the difference in ULPs.
155 return abs(floatIntA.fSignBitInt - floatIntB.fSignBitInt);
156 }
157
158 // cube root approximation using bit hack for 64-bit float
159 // adapted from Kahan's cbrt
cbrt_5d(double d)160 static double cbrt_5d(double d) {
161 const unsigned int B1 = 715094163;
162 double t = 0.0;
163 unsigned int* pt = (unsigned int*) &t;
164 unsigned int* px = (unsigned int*) &d;
165 pt[1] = px[1] / 3 + B1;
166 return t;
167 }
168
169 // iterative cube root approximation using Halley's method (double)
cbrta_halleyd(const double a,const double R)170 static double cbrta_halleyd(const double a, const double R) {
171 const double a3 = a * a * a;
172 const double b = a * (a3 + R + R) / (a3 + a3 + R);
173 return b;
174 }
175
176 // cube root approximation using 3 iterations of Halley's method (double)
halley_cbrt3d(double d)177 static double halley_cbrt3d(double d) {
178 double a = cbrt_5d(d);
179 a = cbrta_halleyd(a, d);
180 a = cbrta_halleyd(a, d);
181 return cbrta_halleyd(a, d);
182 }
183
SkDCubeRoot(double x)184 double SkDCubeRoot(double x) {
185 if (approximately_zero_cubed(x)) {
186 return 0;
187 }
188 double result = halley_cbrt3d(fabs(x));
189 if (x < 0) {
190 result = -result;
191 }
192 return result;
193 }
194