Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkFloatingPoint.h
Go to the documentation of this file.
1/*
2 * Copyright 2006 The Android Open Source Project
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
8#ifndef SkFloatingPoint_DEFINED
9#define SkFloatingPoint_DEFINED
10
13
14#include <cmath>
15#include <cstdint>
16#include <limits>
17#include <type_traits>
18
19inline constexpr float SK_FloatSqrt2 = 1.41421356f;
20inline constexpr float SK_FloatPI = 3.14159265f;
21inline constexpr double SK_DoublePI = 3.14159265358979323846264338327950288;
22
23static constexpr int sk_float_sgn(float x) {
24 return (0.0f < x) - (x < 0.0f);
25}
26
27static constexpr float sk_float_degrees_to_radians(float degrees) {
28 return degrees * (SK_FloatPI / 180);
29}
30
31static constexpr float sk_float_radians_to_degrees(float radians) {
32 return radians * (180 / SK_FloatPI);
33}
34
35// floor(double+0.5) vs. floorf(float+0.5f) give comparable performance, but upcasting to double
36// means tricky values like 0.49999997 and 2^24 get rounded correctly. If these were rounded
37// as floatf(x + .5f), they would be 1 higher than expected.
38#define sk_float_round(x) (float)sk_double_round((double)(x))
39
40template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
41static inline bool SkIsNaN(T x) {
42 return x != x;
43}
44
45// Subtracting a value from itself will result in zero, except for NAN or ±Inf, which make NAN.
46// Multiplying a group of values against zero will result in zero for each product, except for
47// NAN or ±Inf, which will result in NAN and continue resulting in NAN for the rest of the elements.
48// This generates better code than `std::isfinite` when building with clang-cl (April 2024).
49template <typename T, typename... Pack, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
50static inline bool SkIsFinite(T x, Pack... values) {
51 T prod = x - x;
52 prod = (prod * ... * values);
53 // At this point, `prod` will either be NaN or 0.
54 return prod == prod;
55}
56
57template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
58static inline bool SkIsFinite(const T array[], int count) {
59 T x = array[0];
60 T prod = x - x;
61 for (int i = 1; i < count; ++i) {
62 prod *= array[i];
63 }
64 // At this point, `prod` will either be NaN or 0.
65 return prod == prod;
66}
67
68inline constexpr int SK_MaxS32FitsInFloat = 2147483520;
70
71// 0x7fffff8000000000
72inline constexpr int64_t SK_MaxS64FitsInFloat = SK_MaxS64 >> (63-24) << (63-24);
73inline constexpr int64_t SK_MinS64FitsInFloat = -SK_MaxS64FitsInFloat;
74
75/**
76 * Return the closest int for the given float. Returns SK_MaxS32FitsInFloat for NaN.
77 */
78static constexpr int sk_float_saturate2int(float x) {
81 return (int)x;
82}
83
84/**
85 * Return the closest int for the given double. Returns SK_MaxS32 for NaN.
86 */
87static constexpr int sk_double_saturate2int(double x) {
88 x = x < SK_MaxS32 ? x : SK_MaxS32;
89 x = x > SK_MinS32 ? x : SK_MinS32;
90 return (int)x;
91}
92
93/**
94 * Return the closest int64_t for the given float. Returns SK_MaxS64FitsInFloat for NaN.
95 */
96static constexpr int64_t sk_float_saturate2int64(float x) {
99 return (int64_t)x;
100}
101
102#define sk_float_floor2int(x) sk_float_saturate2int(std::floor(x))
103#define sk_float_round2int(x) sk_float_saturate2int(sk_float_round(x))
104#define sk_float_ceil2int(x) sk_float_saturate2int(std::ceil(x))
105
106#define sk_float_floor2int_no_saturate(x) ((int)std::floor(x))
107#define sk_float_round2int_no_saturate(x) ((int)sk_float_round(x))
108#define sk_float_ceil2int_no_saturate(x) ((int)std::ceil(x))
109
110#define sk_double_round(x) (std::floor((x) + 0.5))
111#define sk_double_floor2int(x) ((int)std::floor(x))
112#define sk_double_round2int(x) ((int)std::round(x))
113#define sk_double_ceil2int(x) ((int)std::ceil(x))
114
115// Cast double to float, ignoring any warning about too-large finite values being cast to float.
116// Clang thinks this is undefined, but it's actually implementation defined to return either
117// the largest float or infinity (one of the two bracketing representable floats). Good enough!
118SK_NO_SANITIZE("float-cast-overflow")
119static constexpr float sk_double_to_float(double x) {
120 return static_cast<float>(x);
121}
122
123inline constexpr float SK_FloatNaN = std::numeric_limits<float>::quiet_NaN();
124inline constexpr float SK_FloatInfinity = std::numeric_limits<float>::infinity();
126
127inline constexpr double SK_DoubleNaN = std::numeric_limits<double>::quiet_NaN();
128
129// Calculate the midpoint between a and b. Similar to std::midpoint in c++20.
130static constexpr float sk_float_midpoint(float a, float b) {
131 // Use double math to avoid underflow and overflow.
132 return static_cast<float>(0.5 * (static_cast<double>(a) + b));
133}
134
135static inline float sk_float_rsqrt_portable(float x) { return 1.0f / std::sqrt(x); }
136static inline float sk_float_rsqrt (float x) { return 1.0f / std::sqrt(x); }
137
138// IEEE defines how float divide behaves for non-finite values and zero-denoms, but C does not,
139// so we have a helper that suppresses the possible undefined-behavior warnings.
140#ifdef SK_BUILD_FOR_WIN
141#pragma warning(push)
142#pragma warning(disable : 4723)
143#endif
144SK_NO_SANITIZE("float-divide-by-zero")
145static constexpr float sk_ieee_float_divide(float numer, float denom) {
146 return numer / denom;
147}
148
149SK_NO_SANITIZE("float-divide-by-zero")
150static constexpr double sk_ieee_double_divide(double numer, double denom) {
151 return numer / denom;
152}
153#ifdef SK_BUILD_FOR_WIN
154#pragma warning( pop )
155#endif
156
157// Returns true iff the provided number is within a small epsilon of 0.
158bool sk_double_nearly_zero(double a);
159
160// Compare two doubles and return true if they are within maxUlpsDiff of each other.
161// * nan as a or b - returns false.
162// * infinity, infinity or -infinity, -infinity - returns true.
163// * infinity and any other number - returns false.
164//
165// ulp is an initialism for Units in the Last Place.
166bool sk_doubles_nearly_equal_ulps(double a, double b, uint8_t maxUlpsDiff = 16);
167
168#endif
int count
#define SK_NO_SANITIZE(A)
bool sk_double_nearly_zero(double a)
static constexpr float sk_double_to_float(double x)
constexpr double SK_DoublePI
constexpr float SK_FloatInfinity
constexpr int64_t SK_MinS64FitsInFloat
static bool SkIsFinite(T x, Pack... values)
static bool SkIsNaN(T x)
static constexpr int sk_float_sgn(float x)
static constexpr int64_t sk_float_saturate2int64(float x)
constexpr int64_t SK_MaxS64FitsInFloat
constexpr int SK_MinS32FitsInFloat
constexpr float SK_FloatNaN
static float sk_float_rsqrt_portable(float x)
constexpr float SK_FloatSqrt2
constexpr int SK_MaxS32FitsInFloat
static constexpr float sk_float_degrees_to_radians(float degrees)
static constexpr double sk_ieee_double_divide(double numer, double denom)
constexpr double SK_DoubleNaN
static float sk_float_rsqrt(float x)
static constexpr int sk_double_saturate2int(double x)
static constexpr float sk_ieee_float_divide(float numer, float denom)
static constexpr float sk_float_midpoint(float a, float b)
static constexpr float sk_float_radians_to_degrees(float radians)
static constexpr int sk_float_saturate2int(float x)
constexpr float SK_FloatNegativeInfinity
bool sk_doubles_nearly_equal_ulps(double a, double b, uint8_t maxUlpsDiff=16)
constexpr float SK_FloatPI
static constexpr int64_t SK_MaxS64
Definition SkMath.h:25
static constexpr int32_t SK_MinS32
Definition SkMath.h:22
static constexpr int32_t SK_MaxS32
Definition SkMath.h:21
static bool b
struct MyStruct a[10]
double x
#define T