/* * Copyright 2006 The Android Open Source Project * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file.
*/
// floor(double+0.5) vs. floorf(float+0.5f) give comparable performance, but upcasting to double // means tricky values like 0.49999997 and 2^24 get rounded correctly. If these were rounded // as floatf(x + .5f), they would be 1 higher than expected. #define sk_float_round(x) (float)sk_double_round((double)(x))
// Subtracting a value from itself will result in zero, except for NAN or ±Inf, which make NAN. // Multiplying a group of values against zero will result in zero for each product, except for // NAN or ±Inf, which will result in NAN and continue resulting in NAN for the rest of the elements. // This generates better code than `std::isfinite` when building with clang-cl (April 2024). template <typename T, typename... Pack, std::enable_if_t<std::is_floating_point_v<T>, bool> = true> staticinlinebool SkIsFinite(T x, Pack... values) {
T prod = x - x;
prod = (prod * ... * values); // At this point, `prod` will either be NaN or 0. return prod == prod;
}
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true> staticinlinebool SkIsFinite(const T array[], int count) {
T x = array[0];
T prod = x - x; for (int i = 1; i < count; ++i) {
prod *= array[i];
} // At this point, `prod` will either be NaN or 0. return prod == prod;
}
inline constexpr int SK_MaxS32FitsInFloat = 2147483520; inline constexpr int SK_MinS32FitsInFloat = -SK_MaxS32FitsInFloat;
// sk_[float|double]_saturate2int are written to return their maximum values when passed NaN. // MSVC 19.38+ has a bug with this implementation, leading to incorrect results: // https://developercommunity.visualstudio.com/t/Optimizer-incorrectly-handles-NaN-floati/10654403 // // We inject an explicit NaN test on MSVC to work around the problem. #ifdefined(_MSC_VER) && !defined(__clang__) #define SK_CHECK_NAN(resultVal) if (SkIsNaN(x)) { return resultVal; } #else #define SK_CHECK_NAN(resultVal) #endif
/** * Return the closest int for the given float. Returns SK_MaxS32FitsInFloat for NaN.
*/ static constexpr int sk_float_saturate2int(float x) {
SK_CHECK_NAN(SK_MaxS32FitsInFloat)
x = x < SK_MaxS32FitsInFloat ? x : SK_MaxS32FitsInFloat;
x = x > SK_MinS32FitsInFloat ? x : SK_MinS32FitsInFloat; return (int)x;
}
/** * Return the closest int for the given double. Returns SK_MaxS32 for NaN.
*/ static constexpr int sk_double_saturate2int(double x) {
SK_CHECK_NAN(SK_MaxS32)
x = x < SK_MaxS32 ? x : SK_MaxS32;
x = x > SK_MinS32 ? x : SK_MinS32; return (int)x;
}
/** * Return the closest int64_t for the given float. Returns SK_MaxS64FitsInFloat for NaN.
*/ static constexpr int64_t sk_float_saturate2int64(float x) {
SK_CHECK_NAN(SK_MaxS64FitsInFloat)
x = x < SK_MaxS64FitsInFloat ? x : SK_MaxS64FitsInFloat;
x = x > SK_MinS64FitsInFloat ? x : SK_MinS64FitsInFloat; return (int64_t)x;
}
// Cast double to float, ignoring any warning about too-large finite values being cast to float. // Clang thinks this is undefined, but it's actually implementation defined to return either // the largest float or infinity (one of the two bracketing representable floats). Good enough! #ifdef __clang__
SK_NO_SANITIZE("float-cast-overflow") #elifdefined(__GNUC__)
SK_ATTRIBUTE(no_sanitize_undefined) #endif static constexpr float sk_double_to_float(double x) { returnstatic_cast<float>(x);
}
// Calculate the midpoint between a and b. Similar to std::midpoint in c++20. static constexpr float sk_float_midpoint(float a, float b) { // Use double math to avoid underflow and overflow. returnstatic_cast<float>(0.5 * (static_cast<double>(a) + b));
}
// IEEE defines how float divide behaves for non-finite values and zero-denoms, but C does not, // so we have a helper that suppresses the possible undefined-behavior warnings. #ifdef SK_BUILD_FOR_WIN #pragma warning(push) #pragma warning(disable : 4723) #endif #ifdef __clang__
SK_NO_SANITIZE("float-divide-by-zero") #elifdefined(__GNUC__)
SK_ATTRIBUTE(no_sanitize_undefined) #endif static constexpr float sk_ieee_float_divide(float numer, float denom) { return numer / denom;
}
// Returns true iff the provided number is within a small epsilon of 0. bool sk_double_nearly_zero(double a);
// Compare two doubles and return true if they are within maxUlpsDiff of each other. // * nan as a or b - returns false. // * infinity, infinity or -infinity, -infinity - returns true. // * infinity and any other number - returns false. // // ulp is an initialism for Units in the Last Place. bool sk_doubles_nearly_equal_ulps(double a, double b, uint8_t maxUlpsDiff = 16);
#endif
Messung V0.5
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.