SkPathOpsTypes.cpp revision cffbcc3b9665f2c928544b6fc6b8a0e22a4210fb
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
1007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comconst int UlpsEpsilon = 16;
1107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
1207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// from http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
13cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com// FIXME: move to SkFloatBits.h
1407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.combool AlmostEqualUlps(float A, float B) {
15cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    SkFloatIntUnion floatIntA, floatIntB;
16cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    floatIntA.fFloat = A;
17cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    floatIntB.fFloat = B;
1807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // Different signs means they do not match.
19cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    if ((floatIntA.fSignBitInt < 0) != (floatIntB.fSignBitInt < 0))
2007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    {
2107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        // Check for equality to make sure +0 == -0
2207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return A == B;
2307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
2407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // Find the difference in ULPs.
25cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    int ulpsDiff = abs(floatIntA.fSignBitInt - floatIntB.fSignBitInt);
2607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return ulpsDiff <= UlpsEpsilon;
2707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
2807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
2907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// cube root approximation using bit hack for 64-bit float
3007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// adapted from Kahan's cbrt
31cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.comstatic double cbrt_5d(double d) {
3207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const unsigned int B1 = 715094163;
3307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    double t = 0.0;
3407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    unsigned int* pt = (unsigned int*) &t;
3507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    unsigned int* px = (unsigned int*) &d;
3607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    pt[1] = px[1] / 3 + B1;
3707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return t;
3807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
3907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
4007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// iterative cube root approximation using Halley's method (double)
41cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.comstatic double cbrta_halleyd(const double a, const double R) {
4207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const double a3 = a * a * a;
4307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const double b = a * (a3 + R + R) / (a3 + a3 + R);
4407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return b;
4507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
4607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
4707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// cube root approximation using 3 iterations of Halley's method (double)
4807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comstatic double halley_cbrt3d(double d) {
4907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    double a = cbrt_5d(d);
5007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    a = cbrta_halleyd(a, d);
5107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    a = cbrta_halleyd(a, d);
5207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return cbrta_halleyd(a, d);
5307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
5407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
5507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comdouble SkDCubeRoot(double x) {
5607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (approximately_zero_cubed(x)) {
5707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return 0;
5807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
5907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    double result = halley_cbrt3d(fabs(x));
6007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (x < 0) {
6107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        result = -result;
6207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
6307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return result;
6407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
65