SkPathOpsTypes.cpp revision a2bbc6e19d5332e81784e582c290cc060f40c4c7
107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com/*
207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com * Copyright 2012 Google Inc.
307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com *
407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com * Use of this source code is governed by a BSD-style license that can be
507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com * found in the LICENSE file.
607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com */
7cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com#include "SkFloatBits.h"
807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#include "SkPathOpsTypes.h"
907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
107eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.comstatic bool arguments_denormalized(float a, float b, int epsilon) {
11a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    float denormalizedCheck = FLT_EPSILON * epsilon / 2;
12a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    return fabsf(a) <= denormalizedCheck && fabsf(b) <= denormalizedCheck;
137eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com}
147eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com
1507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// from http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
16cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com// FIXME: move to SkFloatBits.h
17a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.comstatic bool equal_ulps(float a, float b, int epsilon, int depsilon) {
18570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
19570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        return false;
2007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
21a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    if (arguments_denormalized(a, b, depsilon)) {
227eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        return true;
237eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    }
247eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    int aBits = SkFloatAs2sCompliment(a);
257eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    int bBits = SkFloatAs2sCompliment(b);
267eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    // Find the difference in ULPs.
277eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    return aBits < bBits + epsilon && bBits < aBits + epsilon;
287eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com}
297eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com
307eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.comstatic bool d_equal_ulps(float a, float b, int epsilon) {
317eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
327eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        return false;
337eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    }
34570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int aBits = SkFloatAs2sCompliment(a);
35570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int bBits = SkFloatAs2sCompliment(b);
3607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // Find the difference in ULPs.
37570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return aBits < bBits + epsilon && bBits < aBits + epsilon;
38570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
39570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
40570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comstatic bool not_equal_ulps(float a, float b, int epsilon) {
41570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
42570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        return false;
43570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
447eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    if (arguments_denormalized(a, b, epsilon)) {
457eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        return false;
467eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    }
477eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    int aBits = SkFloatAs2sCompliment(a);
487eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    int bBits = SkFloatAs2sCompliment(b);
497eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    // Find the difference in ULPs.
507eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
517eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com}
527eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com
537eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.comstatic bool d_not_equal_ulps(float a, float b, int epsilon) {
547eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
557eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        return false;
567eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    }
57570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int aBits = SkFloatAs2sCompliment(a);
58570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int bBits = SkFloatAs2sCompliment(b);
59570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    // Find the difference in ULPs.
60570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
6107e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com}
6207e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com
634fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.comstatic bool less_ulps(float a, float b, int epsilon) {
64570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
65570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        return false;
66fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com    }
677eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    if (arguments_denormalized(a, b, epsilon)) {
687eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        return a <= b - FLT_EPSILON * epsilon;
697eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    }
70570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int aBits = SkFloatAs2sCompliment(a);
71570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int bBits = SkFloatAs2sCompliment(b);
72fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com    // Find the difference in ULPs.
73570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return aBits <= bBits - epsilon;
74570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
75570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
76570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comstatic bool less_or_equal_ulps(float a, float b, int epsilon) {
77570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
78570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        return false;
79570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
807eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    if (arguments_denormalized(a, b, epsilon)) {
817eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        return a < b + FLT_EPSILON * epsilon;
827eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    }
83570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int aBits = SkFloatAs2sCompliment(a);
84570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int bBits = SkFloatAs2sCompliment(b);
85570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    // Find the difference in ULPs.
86570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return aBits < bBits + epsilon;
87570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
88570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
89570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com// equality using the same error term as between
90570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.combool AlmostBequalUlps(float a, float b) {
91570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const int UlpsEpsilon = 2;
92a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
93a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com}
94a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com
95a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.combool AlmostPequalUlps(float a, float b) {
96a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    const int UlpsEpsilon = 8;
97a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
98fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com}
99fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com
1007eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.combool AlmostDequalUlps(float a, float b) {
1017eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    const int UlpsEpsilon = 16;
1027eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    return d_equal_ulps(a, b, UlpsEpsilon);
1037eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com}
1047eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com
1054fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.combool AlmostEqualUlps(float a, float b) {
10607e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com    const int UlpsEpsilon = 16;
107a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
10807e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com}
10907e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com
110570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.combool NotAlmostEqualUlps(float a, float b) {
111570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const int UlpsEpsilon = 16;
112570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return not_equal_ulps(a, b, UlpsEpsilon);
113570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
114570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
1157eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.combool NotAlmostDequalUlps(float a, float b) {
1167eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    const int UlpsEpsilon = 16;
1177eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    return d_not_equal_ulps(a, b, UlpsEpsilon);
1187eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com}
1197eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com
1204fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.combool RoughlyEqualUlps(float a, float b) {
12107e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com    const int UlpsEpsilon = 256;
122a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    const int DUlpsEpsilon = 1024;
123a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    return equal_ulps(a, b, UlpsEpsilon, DUlpsEpsilon);
12407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
12507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
126fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.combool AlmostBetweenUlps(float a, float b, float c) {
127570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const int UlpsEpsilon = 2;
128570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return a <= c ? less_or_equal_ulps(a, b, UlpsEpsilon) && less_or_equal_ulps(b, c, UlpsEpsilon)
129570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        : less_or_equal_ulps(b, a, UlpsEpsilon) && less_or_equal_ulps(c, b, UlpsEpsilon);
130570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
131570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
132570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.combool AlmostLessUlps(float a, float b) {
133570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const int UlpsEpsilon = 16;
134570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return less_ulps(a, b, UlpsEpsilon);
135570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
136570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
137570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.combool AlmostLessOrEqualUlps(float a, float b) {
138570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const int UlpsEpsilon = 16;
139570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return less_or_equal_ulps(a, b, UlpsEpsilon);
140fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com}
141fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com
1424fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.comint UlpsDistance(float a, float b) {
143570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
144570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        return SK_MaxS32;
145570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
1464fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com    SkFloatIntUnion floatIntA, floatIntB;
1474fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com    floatIntA.fFloat = a;
1484fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com    floatIntB.fFloat = b;
1494fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com    // Different signs means they do not match.
1504fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com    if ((floatIntA.fSignBitInt < 0) != (floatIntB.fSignBitInt < 0)) {
1514fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com        // Check for equality to make sure +0 == -0
1524fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com        return a == b ? 0 : SK_MaxS32;
1534fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com    }
1544fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com    // Find the difference in ULPs.
1554fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com    return abs(floatIntA.fSignBitInt - floatIntB.fSignBitInt);
1564fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com}
1574fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com
15807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// cube root approximation using bit hack for 64-bit float
15907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// adapted from Kahan's cbrt
160cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.comstatic double cbrt_5d(double d) {
16107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const unsigned int B1 = 715094163;
16207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    double t = 0.0;
16307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    unsigned int* pt = (unsigned int*) &t;
16407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    unsigned int* px = (unsigned int*) &d;
16507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    pt[1] = px[1] / 3 + B1;
16607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return t;
16707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
16807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
16907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// iterative cube root approximation using Halley's method (double)
170cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.comstatic double cbrta_halleyd(const double a, const double R) {
17107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const double a3 = a * a * a;
17207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const double b = a * (a3 + R + R) / (a3 + a3 + R);
17307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return b;
17407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
17507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
17607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// cube root approximation using 3 iterations of Halley's method (double)
17707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comstatic double halley_cbrt3d(double d) {
17807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    double a = cbrt_5d(d);
17907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    a = cbrta_halleyd(a, d);
18007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    a = cbrta_halleyd(a, d);
18107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return cbrta_halleyd(a, d);
18207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
18307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
18407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comdouble SkDCubeRoot(double x) {
18507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (approximately_zero_cubed(x)) {
18607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return 0;
18707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
18807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    double result = halley_cbrt3d(fabs(x));
18907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (x < 0) {
19007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        result = -result;
19107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
19207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return result;
19307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
194