blob: 6cb4cf1542f37c9c4c16b1b66673bb4c0692bf95 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
8#ifndef SkFloatingPoint_DEFINED
9#define SkFloatingPoint_DEFINED
10
Mike Reed35ee0e02017-08-06 22:29:57 -040011#include "../private/SkFloatBits.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkTypes.h"
Mike Kleine9f78b42016-11-22 08:57:45 -050013#include "SkSafe_math.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include <float.h>
Mike Reed9236b022018-05-14 13:37:16 -040015#include <math.h>
bungeman@google.comd3fbd342014-04-15 15:52:07 +000016
mtkleine18fa442016-06-09 13:40:56 -070017#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE1
18 #include <xmmintrin.h>
19#elif defined(SK_ARM_HAS_NEON)
20 #include <arm_neon.h>
21#endif
22
bungeman@google.comd3fbd342014-04-15 15:52:07 +000023// For _POSIX_VERSION
24#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
25#include <unistd.h>
26#endif
27
bungeman@google.com0567f222012-07-25 17:00:47 +000028// C++98 cmath std::pow seems to be the earliest portable way to get float pow.
29// However, on Linux including cmath undefines isfinite.
30// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14608
reed@android.com9c970452009-04-03 14:26:10 +000031static inline float sk_float_pow(float base, float exp) {
bungeman@google.com0567f222012-07-25 17:00:47 +000032 return powf(base, exp);
reed@android.com9c970452009-04-03 14:26:10 +000033}
34
bungeman028205b2015-07-29 12:34:25 -070035#define sk_float_sqrt(x) sqrtf(x)
36#define sk_float_sin(x) sinf(x)
37#define sk_float_cos(x) cosf(x)
38#define sk_float_tan(x) tanf(x)
39#define sk_float_floor(x) floorf(x)
40#define sk_float_ceil(x) ceilf(x)
bungemandd67e3d2016-03-10 13:39:30 -080041#define sk_float_trunc(x) truncf(x)
reed@android.com8a1c16f2008-12-17 15:59:43 +000042#ifdef SK_BUILD_FOR_MAC
bungeman028205b2015-07-29 12:34:25 -070043# define sk_float_acos(x) static_cast<float>(acos(x))
44# define sk_float_asin(x) static_cast<float>(asin(x))
reed@android.com8a1c16f2008-12-17 15:59:43 +000045#else
bungeman028205b2015-07-29 12:34:25 -070046# define sk_float_acos(x) acosf(x)
47# define sk_float_asin(x) asinf(x)
reed@android.com8a1c16f2008-12-17 15:59:43 +000048#endif
bungeman028205b2015-07-29 12:34:25 -070049#define sk_float_atan2(y,x) atan2f(y,x)
50#define sk_float_abs(x) fabsf(x)
bungemand7dc76f2016-03-10 11:14:40 -080051#define sk_float_copysign(x, y) copysignf(x, y)
bungeman028205b2015-07-29 12:34:25 -070052#define sk_float_mod(x,y) fmodf(x,y)
53#define sk_float_exp(x) expf(x)
54#define sk_float_log(x) logf(x)
reed@android.com8a1c16f2008-12-17 15:59:43 +000055
mtklein1831f992015-06-09 11:47:01 -070056#define sk_float_round(x) sk_float_floor((x) + 0.5f)
57
reed7729e562015-01-16 08:35:09 -080058// can't find log2f on android, but maybe that just a tool bug?
59#ifdef SK_BUILD_FOR_ANDROID
60 static inline float sk_float_log2(float x) {
61 const double inv_ln_2 = 1.44269504088896;
62 return (float)(log(x) * inv_ln_2);
63 }
64#else
65 #define sk_float_log2(x) log2f(x)
66#endif
67
Mike Reed9236b022018-05-14 13:37:16 -040068static inline bool sk_float_isfinite(float x) {
69 return SkFloatBits_IsFinite(SkFloat2Bits(x));
70}
71
72static inline bool sk_float_isinf(float x) {
73 return SkFloatBits_IsInf(SkFloat2Bits(x));
74}
75
76static inline bool sk_float_isnan(float x) {
77 return !(x == x);
78}
reed@google.com61873a52011-12-05 21:47:25 +000079
caryclark@google.com3b97af52013-04-23 11:56:44 +000080#define sk_double_isnan(a) sk_float_isnan(a)
81
Mike Reed828f1d52017-08-09 11:06:53 -040082#define SK_MaxS32FitsInFloat 2147483520
83#define SK_MinS32FitsInFloat -SK_MaxS32FitsInFloat
84
Mike Reed3d5a6b52018-01-31 15:55:47 -050085#define SK_MaxS64FitsInFloat (SK_MaxS64 >> (63-24) << (63-24)) // 0x7fffff8000000000
86#define SK_MinS64FitsInFloat -SK_MaxS64FitsInFloat
87
Mike Reed828f1d52017-08-09 11:06:53 -040088/**
89 * Return the closest int for the given float. Returns SK_MaxS32FitsInFloat for NaN.
90 */
91static inline int sk_float_saturate2int(float x) {
92 x = SkTMin<float>(x, SK_MaxS32FitsInFloat);
93 x = SkTMax<float>(x, SK_MinS32FitsInFloat);
94 return (int)x;
95}
96
Mike Reede0762232017-10-10 14:49:35 -040097/**
98 * Return the closest int for the given double. Returns SK_MaxS32 for NaN.
99 */
100static inline int sk_double_saturate2int(double x) {
101 x = SkTMin<double>(x, SK_MaxS32);
102 x = SkTMax<double>(x, SK_MinS32);
103 return (int)x;
104}
105
Mike Reed3d5a6b52018-01-31 15:55:47 -0500106/**
107 * Return the closest int64_t for the given float. Returns SK_MaxS64FitsInFloat for NaN.
108 */
109static inline int64_t sk_float_saturate2int64(float x) {
110 x = SkTMin<float>(x, SK_MaxS64FitsInFloat);
111 x = SkTMax<float>(x, SK_MinS64FitsInFloat);
112 return (int64_t)x;
113}
114
Mike Reed828f1d52017-08-09 11:06:53 -0400115#define sk_float_floor2int(x) sk_float_saturate2int(sk_float_floor(x))
116#define sk_float_round2int(x) sk_float_saturate2int(sk_float_floor((x) + 0.5f))
117#define sk_float_ceil2int(x) sk_float_saturate2int(sk_float_ceil(x))
118
119#define sk_float_floor2int_no_saturate(x) (int)sk_float_floor(x)
120#define sk_float_round2int_no_saturate(x) (int)sk_float_floor((x) + 0.5f)
121#define sk_float_ceil2int_no_saturate(x) (int)sk_float_ceil(x)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122
reed39393e32014-10-21 12:33:21 -0700123#define sk_double_floor(x) floor(x)
124#define sk_double_round(x) floor((x) + 0.5)
125#define sk_double_ceil(x) ceil(x)
126#define sk_double_floor2int(x) (int)floor(x)
Mike Reedee430912018-05-23 12:12:21 -0400127#define sk_double_round2int(x) (int)floor((x) + 0.5)
reed39393e32014-10-21 12:33:21 -0700128#define sk_double_ceil2int(x) (int)ceil(x)
129
Mike Klein7791b942017-09-18 09:46:16 -0400130// Cast double to float, ignoring any warning about too-large finite values being cast to float.
131// Clang thinks this is undefined, but it's actually implementation defined to return either
132// the largest float or infinity (one of the two bracketing representable floats). Good enough!
Mike Klein5e996b82017-09-21 13:56:05 -0400133#if defined(__clang__) && (__clang_major__ * 1000 + __clang_minor__) >= 3007
Ben Wagner05c474b2017-09-15 17:48:08 -0400134__attribute__((no_sanitize("float-cast-overflow")))
135#endif
136static inline float sk_double_to_float(double x) {
137 return static_cast<float>(x);
138}
139
mtklein3ff2cc82016-08-10 08:31:42 -0700140static const uint32_t kIEEENotANumber = 0x7fffffff;
141#define SK_FloatNaN (*SkTCast<const float*>(&kIEEENotANumber))
142#define SK_FloatInfinity (+(float)INFINITY)
143#define SK_FloatNegativeInfinity (-(float)INFINITY)
commit-bot@chromium.org11e5b972013-11-08 20:14:16 +0000144
mtkleina766ca82016-01-26 07:40:30 -0800145static inline float sk_float_rsqrt_portable(float x) {
146 // Get initial estimate.
Mike Klein1e114f12016-09-29 11:15:15 -0400147 int i;
148 memcpy(&i, &x, 4);
mtkleina766ca82016-01-26 07:40:30 -0800149 i = 0x5F1FFFF9 - (i>>1);
Mike Klein1e114f12016-09-29 11:15:15 -0400150 float estimate;
151 memcpy(&estimate, &i, 4);
mtkleina766ca82016-01-26 07:40:30 -0800152
153 // One step of Newton's method to refine.
154 const float estimate_sq = estimate*estimate;
155 estimate *= 0.703952253f*(2.38924456f-x*estimate_sq);
156 return estimate;
157}
mtklein490b6152015-07-31 11:50:27 -0700158
commit-bot@chromium.org11e5b972013-11-08 20:14:16 +0000159// Fast, approximate inverse square root.
160// Compare to name-brand "1.0f / sk_float_sqrt(x)". Should be around 10x faster on SSE, 2x on NEON.
mtkleina766ca82016-01-26 07:40:30 -0800161static inline float sk_float_rsqrt(float x) {
commit-bot@chromium.org11e5b972013-11-08 20:14:16 +0000162// We want all this inlined, so we'll inline SIMD and just take the hit when we don't know we've got
163// it at compile time. This is going to be too fast to productively hide behind a function pointer.
164//
mtkleina766ca82016-01-26 07:40:30 -0800165// We do one step of Newton's method to refine the estimates in the NEON and portable paths. No
commit-bot@chromium.org11e5b972013-11-08 20:14:16 +0000166// refinement is faster, but very innacurate. Two steps is more accurate, but slower than 1/sqrt.
jvanverth29c69792015-07-23 11:14:29 -0700167//
mtkleina766ca82016-01-26 07:40:30 -0800168// Optimized constants in the portable path courtesy of http://rrrola.wz.cz/inv_sqrt.html
mtkleinb9c47f92015-07-23 08:37:02 -0700169#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE1
170 return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x)));
djsollen21769c52014-08-01 05:32:32 -0700171#elif defined(SK_ARM_HAS_NEON)
commit-bot@chromium.org11e5b972013-11-08 20:14:16 +0000172 // Get initial estimate.
173 const float32x2_t xx = vdup_n_f32(x); // Clever readers will note we're doing everything 2x.
174 float32x2_t estimate = vrsqrte_f32(xx);
175
176 // One step of Newton's method to refine.
177 const float32x2_t estimate_sq = vmul_f32(estimate, estimate);
178 estimate = vmul_f32(estimate, vrsqrts_f32(xx, estimate_sq));
179 return vget_lane_f32(estimate, 0); // 1 will work fine too; the answer's in both places.
180#else
mtkleina766ca82016-01-26 07:40:30 -0800181 return sk_float_rsqrt_portable(x);
commit-bot@chromium.org11e5b972013-11-08 20:14:16 +0000182#endif
183}
184
joshualitt922c8b12015-08-07 09:55:23 -0700185// This is the number of significant digits we can print in a string such that when we read that
186// string back we get the floating point number we expect. The minimum value C requires is 6, but
187// most compilers support 9
188#ifdef FLT_DECIMAL_DIG
189#define SK_FLT_DECIMAL_DIG FLT_DECIMAL_DIG
190#else
191#define SK_FLT_DECIMAL_DIG 9
192#endif
193
Mike Reedfaffa862018-02-12 11:46:19 -0500194// IEEE defines how float divide behaves for non-finite values and zero-denoms, but C does not
195// so we have a helper that suppresses the possible undefined-behavior warnings.
196
197#ifdef __clang__
198__attribute__((no_sanitize("float-divide-by-zero")))
199#endif
200static inline float sk_ieee_float_divide(float numer, float denom) {
201 return numer / denom;
202}
203
Mike Reed9236b022018-05-14 13:37:16 -0400204#ifdef __clang__
205__attribute__((no_sanitize("float-divide-by-zero")))
206#endif
207static inline double sk_ieee_double_divide(double numer, double denom) {
208 return numer / denom;
209}
210
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211#endif