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 "src/pathops/SkPathOpsTypes.h"
8
9 #include "include/private/base/SkFloatingPoint.h"
10 #include "include/private/base/SkMath.h"
11 #include "include/private/base/SkTemplates.h"
12 #include "src/base/SkFloatBits.h"
13
14 #include <algorithm>
15 #include <cstdint>
16 #include <cstring>
17
arguments_denormalized(float a,float b,int epsilon)18 static bool arguments_denormalized(float a, float b, int epsilon) {
19 float denormalizedCheck = FLT_EPSILON * epsilon / 2;
20 return fabsf(a) <= denormalizedCheck && fabsf(b) <= denormalizedCheck;
21 }
22
23 // from http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
24 // FIXME: move to SkFloatBits.h
equal_ulps(float a,float b,int epsilon,int depsilon)25 static bool equal_ulps(float a, float b, int epsilon, int depsilon) {
26 if (arguments_denormalized(a, b, depsilon)) {
27 return true;
28 }
29 int aBits = SkFloatAs2sCompliment(a);
30 int bBits = SkFloatAs2sCompliment(b);
31 // Find the difference in ULPs.
32 return aBits < bBits + epsilon && bBits < aBits + epsilon;
33 }
34
equal_ulps_no_normal_check(float a,float b,int epsilon,int depsilon)35 static bool equal_ulps_no_normal_check(float a, float b, int epsilon, int depsilon) {
36 int aBits = SkFloatAs2sCompliment(a);
37 int bBits = SkFloatAs2sCompliment(b);
38 // Find the difference in ULPs.
39 return aBits < bBits + epsilon && bBits < aBits + epsilon;
40 }
41
equal_ulps_pin(float a,float b,int epsilon,int depsilon)42 static bool equal_ulps_pin(float a, float b, int epsilon, int depsilon) {
43 if (!SkIsFinite(a, b)) {
44 return false;
45 }
46 if (arguments_denormalized(a, b, depsilon)) {
47 return true;
48 }
49 int aBits = SkFloatAs2sCompliment(a);
50 int bBits = SkFloatAs2sCompliment(b);
51 // Find the difference in ULPs.
52 return aBits < bBits + epsilon && bBits < aBits + epsilon;
53 }
54
d_equal_ulps(float a,float b,int epsilon)55 static bool d_equal_ulps(float a, float b, int epsilon) {
56 int aBits = SkFloatAs2sCompliment(a);
57 int bBits = SkFloatAs2sCompliment(b);
58 // Find the difference in ULPs.
59 return aBits < bBits + epsilon && bBits < aBits + epsilon;
60 }
61
not_equal_ulps(float a,float b,int epsilon)62 static bool not_equal_ulps(float a, float b, int epsilon) {
63 if (arguments_denormalized(a, b, epsilon)) {
64 return false;
65 }
66 int aBits = SkFloatAs2sCompliment(a);
67 int bBits = SkFloatAs2sCompliment(b);
68 // Find the difference in ULPs.
69 return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
70 }
71
not_equal_ulps_pin(float a,float b,int epsilon)72 static bool not_equal_ulps_pin(float a, float b, int epsilon) {
73 if (!SkIsFinite(a, b)) {
74 return false;
75 }
76 if (arguments_denormalized(a, b, epsilon)) {
77 return false;
78 }
79 int aBits = SkFloatAs2sCompliment(a);
80 int bBits = SkFloatAs2sCompliment(b);
81 // Find the difference in ULPs.
82 return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
83 }
84
d_not_equal_ulps(float a,float b,int epsilon)85 static bool d_not_equal_ulps(float a, float b, int epsilon) {
86 int aBits = SkFloatAs2sCompliment(a);
87 int bBits = SkFloatAs2sCompliment(b);
88 // Find the difference in ULPs.
89 return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
90 }
91
less_ulps(float a,float b,int epsilon)92 static bool less_ulps(float a, float b, int epsilon) {
93 if (arguments_denormalized(a, b, epsilon)) {
94 return a <= b - FLT_EPSILON * epsilon;
95 }
96 int aBits = SkFloatAs2sCompliment(a);
97 int bBits = SkFloatAs2sCompliment(b);
98 // Find the difference in ULPs.
99 return aBits <= bBits - epsilon;
100 }
101
less_or_equal_ulps(float a,float b,int epsilon)102 static bool less_or_equal_ulps(float a, float b, int epsilon) {
103 if (arguments_denormalized(a, b, epsilon)) {
104 return a < b + FLT_EPSILON * epsilon;
105 }
106 int aBits = SkFloatAs2sCompliment(a);
107 int bBits = SkFloatAs2sCompliment(b);
108 // Find the difference in ULPs.
109 return aBits < bBits + epsilon;
110 }
111
112 // equality using the same error term as between
AlmostBequalUlps(float a,float b)113 bool AlmostBequalUlps(float a, float b) {
114 const int UlpsEpsilon = 2;
115 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
116 }
117
AlmostPequalUlps(float a,float b)118 bool AlmostPequalUlps(float a, float b) {
119 const int UlpsEpsilon = 8;
120 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
121 }
122
AlmostDequalUlps(float a,float b)123 bool AlmostDequalUlps(float a, float b) {
124 const int UlpsEpsilon = 16;
125 return d_equal_ulps(a, b, UlpsEpsilon);
126 }
127
AlmostDequalUlps(double a,double b)128 bool AlmostDequalUlps(double a, double b) {
129 if (fabs(a) < SK_ScalarMax && fabs(b) < SK_ScalarMax) {
130 return AlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
131 }
132 // We allow divide-by-zero here. It only happens if one of a,b is zero, and the other is NaN.
133 // (Otherwise, we'd hit the condition above). Thus, if std::max returns 0, we compute NaN / 0,
134 // which will produce NaN. The comparison will return false, which is the correct answer.
135 return sk_ieee_double_divide(fabs(a - b), std::max(fabs(a), fabs(b))) < FLT_EPSILON * 16;
136 }
137
AlmostEqualUlps(float a,float b)138 bool AlmostEqualUlps(float a, float b) {
139 const int UlpsEpsilon = 16;
140 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
141 }
142
AlmostEqualUlpsNoNormalCheck(float a,float b)143 bool AlmostEqualUlpsNoNormalCheck(float a, float b) {
144 const int UlpsEpsilon = 16;
145 return equal_ulps_no_normal_check(a, b, UlpsEpsilon, UlpsEpsilon);
146 }
147
AlmostEqualUlps_Pin(float a,float b)148 bool AlmostEqualUlps_Pin(float a, float b) {
149 const int UlpsEpsilon = 16;
150 return equal_ulps_pin(a, b, UlpsEpsilon, UlpsEpsilon);
151 }
152
NotAlmostEqualUlps(float a,float b)153 bool NotAlmostEqualUlps(float a, float b) {
154 const int UlpsEpsilon = 16;
155 return not_equal_ulps(a, b, UlpsEpsilon);
156 }
157
NotAlmostEqualUlps_Pin(float a,float b)158 bool NotAlmostEqualUlps_Pin(float a, float b) {
159 const int UlpsEpsilon = 16;
160 return not_equal_ulps_pin(a, b, UlpsEpsilon);
161 }
162
NotAlmostDequalUlps(float a,float b)163 bool NotAlmostDequalUlps(float a, float b) {
164 const int UlpsEpsilon = 16;
165 return d_not_equal_ulps(a, b, UlpsEpsilon);
166 }
167
RoughlyEqualUlps(float a,float b)168 bool RoughlyEqualUlps(float a, float b) {
169 const int UlpsEpsilon = 256;
170 const int DUlpsEpsilon = 1024;
171 return equal_ulps(a, b, UlpsEpsilon, DUlpsEpsilon);
172 }
173
AlmostBetweenUlps(float a,float b,float c)174 bool AlmostBetweenUlps(float a, float b, float c) {
175 const int UlpsEpsilon = 2;
176 return a <= c ? less_or_equal_ulps(a, b, UlpsEpsilon) && less_or_equal_ulps(b, c, UlpsEpsilon)
177 : less_or_equal_ulps(b, a, UlpsEpsilon) && less_or_equal_ulps(c, b, UlpsEpsilon);
178 }
179
AlmostLessUlps(float a,float b)180 bool AlmostLessUlps(float a, float b) {
181 const int UlpsEpsilon = 16;
182 return less_ulps(a, b, UlpsEpsilon);
183 }
184
AlmostLessOrEqualUlps(float a,float b)185 bool AlmostLessOrEqualUlps(float a, float b) {
186 const int UlpsEpsilon = 16;
187 return less_or_equal_ulps(a, b, UlpsEpsilon);
188 }
189
UlpsDistance(float a,float b)190 int UlpsDistance(float a, float b) {
191 int32_t floatIntA, floatIntB;
192 memcpy(&floatIntA, &a, sizeof(int32_t));
193 memcpy(&floatIntB, &b, sizeof(int32_t));
194 // Different signs means they do not match.
195 if ((floatIntA < 0) != (floatIntB < 0)) {
196 // Check for equality to make sure +0 == -0
197 return a == b ? 0 : SK_MaxS32;
198 }
199 // Find the difference in ULPs.
200 return SkTAbs(floatIntA - floatIntB);
201 }
202
SkOpGlobalState(SkOpContourHead * head,SkArenaAlloc * allocator SkDEBUGPARAMS (bool debugSkipAssert)SkDEBUGPARAMS (const char * testName))203 SkOpGlobalState::SkOpGlobalState(SkOpContourHead* head,
204 SkArenaAlloc* allocator
205 SkDEBUGPARAMS(bool debugSkipAssert)
206 SkDEBUGPARAMS(const char* testName))
207 : fAllocator(allocator)
208 , fCoincidence(nullptr)
209 , fContourHead(head)
210 , fNested(0)
211 , fWindingFailed(false)
212 , fPhase(SkOpPhase::kIntersecting)
213 SkDEBUGPARAMS(fDebugTestName(testName))
214 SkDEBUGPARAMS(fAngleID(0))
215 SkDEBUGPARAMS(fCoinID(0))
216 SkDEBUGPARAMS(fContourID(0))
217 SkDEBUGPARAMS(fPtTID(0))
218 SkDEBUGPARAMS(fSegmentID(0))
219 SkDEBUGPARAMS(fSpanID(0))
220 SkDEBUGPARAMS(fDebugSkipAssert(debugSkipAssert)) {
221 #if DEBUG_T_SECT_LOOP_COUNT
222 debugResetLoopCounts();
223 #endif
224 #if DEBUG_COIN
225 fPreviousFuncName = nullptr;
226 #endif
227 }
228