blob: bf43c1465942fe985de9230905872977b023918e [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
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 */
caryclark@google.comcffbcc32013-06-04 17:59:42 +00007#include "SkFloatBits.h"
caryclark27c8eb82015-07-06 11:38:33 -07008#include "SkOpCoincidence.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +00009#include "SkPathOpsTypes.h"
10
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000011static bool arguments_denormalized(float a, float b, int epsilon) {
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +000012 float denormalizedCheck = FLT_EPSILON * epsilon / 2;
13 return fabsf(a) <= denormalizedCheck && fabsf(b) <= denormalizedCheck;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000014}
15
caryclark@google.com07393ca2013-04-08 11:47:37 +000016// from http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
caryclark@google.comcffbcc32013-06-04 17:59:42 +000017// FIXME: move to SkFloatBits.h
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +000018static bool equal_ulps(float a, float b, int epsilon, int depsilon) {
caryclark@google.com570863f2013-09-16 15:55:01 +000019 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
20 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +000021 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +000022 if (arguments_denormalized(a, b, depsilon)) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000023 return true;
24 }
25 int aBits = SkFloatAs2sCompliment(a);
26 int bBits = SkFloatAs2sCompliment(b);
27 // Find the difference in ULPs.
28 return aBits < bBits + epsilon && bBits < aBits + epsilon;
29}
30
31static bool d_equal_ulps(float a, float b, int epsilon) {
32 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
33 return false;
34 }
caryclark@google.com570863f2013-09-16 15:55:01 +000035 int aBits = SkFloatAs2sCompliment(a);
36 int bBits = SkFloatAs2sCompliment(b);
caryclark@google.com07393ca2013-04-08 11:47:37 +000037 // Find the difference in ULPs.
caryclark@google.com570863f2013-09-16 15:55:01 +000038 return aBits < bBits + epsilon && bBits < aBits + epsilon;
39}
40
41static bool not_equal_ulps(float a, float b, int epsilon) {
42 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
43 return false;
44 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000045 if (arguments_denormalized(a, b, epsilon)) {
46 return false;
47 }
48 int aBits = SkFloatAs2sCompliment(a);
49 int bBits = SkFloatAs2sCompliment(b);
50 // Find the difference in ULPs.
51 return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
52}
53
54static bool d_not_equal_ulps(float a, float b, int epsilon) {
55 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
56 return false;
57 }
caryclark@google.com570863f2013-09-16 15:55:01 +000058 int aBits = SkFloatAs2sCompliment(a);
59 int bBits = SkFloatAs2sCompliment(b);
60 // Find the difference in ULPs.
61 return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
caryclark@google.com07e97fc2013-07-08 17:17:02 +000062}
63
caryclark@google.com4fdbb222013-07-23 15:27:41 +000064static bool less_ulps(float a, float b, int epsilon) {
caryclark@google.com570863f2013-09-16 15:55:01 +000065 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
66 return false;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +000067 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000068 if (arguments_denormalized(a, b, epsilon)) {
69 return a <= b - FLT_EPSILON * epsilon;
70 }
caryclark@google.com570863f2013-09-16 15:55:01 +000071 int aBits = SkFloatAs2sCompliment(a);
72 int bBits = SkFloatAs2sCompliment(b);
caryclark@google.comfa2aeee2013-07-15 13:29:13 +000073 // Find the difference in ULPs.
caryclark@google.com570863f2013-09-16 15:55:01 +000074 return aBits <= bBits - epsilon;
75}
76
77static bool less_or_equal_ulps(float a, float b, int epsilon) {
78 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
79 return false;
80 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000081 if (arguments_denormalized(a, b, epsilon)) {
82 return a < b + FLT_EPSILON * epsilon;
83 }
caryclark@google.com570863f2013-09-16 15:55:01 +000084 int aBits = SkFloatAs2sCompliment(a);
85 int bBits = SkFloatAs2sCompliment(b);
86 // Find the difference in ULPs.
87 return aBits < bBits + epsilon;
88}
89
90// equality using the same error term as between
91bool AlmostBequalUlps(float a, float b) {
92 const int UlpsEpsilon = 2;
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +000093 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
94}
95
96bool AlmostPequalUlps(float a, float b) {
97 const int UlpsEpsilon = 8;
98 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
caryclark@google.comfa2aeee2013-07-15 13:29:13 +000099}
100
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000101bool AlmostDequalUlps(float a, float b) {
102 const int UlpsEpsilon = 16;
103 return d_equal_ulps(a, b, UlpsEpsilon);
104}
105
commit-bot@chromium.org2db7fe72014-05-07 15:31:40 +0000106bool AlmostDequalUlps(double a, double b) {
107 if (SkScalarIsFinite(a) || SkScalarIsFinite(b)) {
108 return AlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
109 }
110 return fabs(a - b) / SkTMax(fabs(a), fabs(b)) < FLT_EPSILON * 16;
111}
112
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000113bool AlmostEqualUlps(float a, float b) {
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000114 const int UlpsEpsilon = 16;
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000115 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000116}
117
caryclark@google.com570863f2013-09-16 15:55:01 +0000118bool NotAlmostEqualUlps(float a, float b) {
119 const int UlpsEpsilon = 16;
120 return not_equal_ulps(a, b, UlpsEpsilon);
121}
122
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000123bool NotAlmostDequalUlps(float a, float b) {
124 const int UlpsEpsilon = 16;
125 return d_not_equal_ulps(a, b, UlpsEpsilon);
126}
127
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000128bool RoughlyEqualUlps(float a, float b) {
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000129 const int UlpsEpsilon = 256;
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000130 const int DUlpsEpsilon = 1024;
131 return equal_ulps(a, b, UlpsEpsilon, DUlpsEpsilon);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000132}
133
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000134bool AlmostBetweenUlps(float a, float b, float c) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000135 const int UlpsEpsilon = 2;
136 return a <= c ? less_or_equal_ulps(a, b, UlpsEpsilon) && less_or_equal_ulps(b, c, UlpsEpsilon)
137 : less_or_equal_ulps(b, a, UlpsEpsilon) && less_or_equal_ulps(c, b, UlpsEpsilon);
138}
139
140bool AlmostLessUlps(float a, float b) {
141 const int UlpsEpsilon = 16;
142 return less_ulps(a, b, UlpsEpsilon);
143}
144
145bool AlmostLessOrEqualUlps(float a, float b) {
146 const int UlpsEpsilon = 16;
147 return less_or_equal_ulps(a, b, UlpsEpsilon);
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000148}
149
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000150int UlpsDistance(float a, float b) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000151 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
152 return SK_MaxS32;
153 }
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000154 SkFloatIntUnion floatIntA, floatIntB;
155 floatIntA.fFloat = a;
156 floatIntB.fFloat = b;
157 // Different signs means they do not match.
158 if ((floatIntA.fSignBitInt < 0) != (floatIntB.fSignBitInt < 0)) {
159 // Check for equality to make sure +0 == -0
160 return a == b ? 0 : SK_MaxS32;
161 }
162 // Find the difference in ULPs.
bungeman60e0fee2015-08-26 05:15:46 -0700163 return SkTAbs(floatIntA.fSignBitInt - floatIntB.fSignBitInt);
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000164}
165
caryclark@google.com07393ca2013-04-08 11:47:37 +0000166// cube root approximation using bit hack for 64-bit float
167// adapted from Kahan's cbrt
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000168static double cbrt_5d(double d) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000169 const unsigned int B1 = 715094163;
170 double t = 0.0;
171 unsigned int* pt = (unsigned int*) &t;
172 unsigned int* px = (unsigned int*) &d;
173 pt[1] = px[1] / 3 + B1;
174 return t;
175}
176
177// iterative cube root approximation using Halley's method (double)
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000178static double cbrta_halleyd(const double a, const double R) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000179 const double a3 = a * a * a;
180 const double b = a * (a3 + R + R) / (a3 + a3 + R);
181 return b;
182}
183
184// cube root approximation using 3 iterations of Halley's method (double)
185static double halley_cbrt3d(double d) {
186 double a = cbrt_5d(d);
187 a = cbrta_halleyd(a, d);
188 a = cbrta_halleyd(a, d);
189 return cbrta_halleyd(a, d);
190}
191
192double SkDCubeRoot(double x) {
193 if (approximately_zero_cubed(x)) {
194 return 0;
195 }
196 double result = halley_cbrt3d(fabs(x));
197 if (x < 0) {
198 result = -result;
199 }
200 return result;
201}
caryclark27c8eb82015-07-06 11:38:33 -0700202
caryclarkd4349722015-07-23 12:40:22 -0700203SkOpGlobalState::SkOpGlobalState(SkOpCoincidence* coincidence, SkOpContourHead* head
204 SkDEBUGPARAMS(const char* testName))
caryclark27c8eb82015-07-06 11:38:33 -0700205 : fCoincidence(coincidence)
206 , fContourHead(head)
207 , fNested(0)
208 , fWindingFailed(false)
209 , fAngleCoincidence(false)
210 , fPhase(kIntersecting)
caryclarkd4349722015-07-23 12:40:22 -0700211 SkDEBUGPARAMS(fDebugTestName(testName))
caryclark27c8eb82015-07-06 11:38:33 -0700212 SkDEBUGPARAMS(fAngleID(0))
213 SkDEBUGPARAMS(fContourID(0))
214 SkDEBUGPARAMS(fPtTID(0))
215 SkDEBUGPARAMS(fSegmentID(0))
216 SkDEBUGPARAMS(fSpanID(0)) {
217 if (coincidence) {
218 coincidence->debugSetGlobalState(this);
219 }
220}
221