19#include "QtCore/private/qglobal_p.h"
20#include "QtCore/qnumeric.h"
21#include "QtCore/qsimd.h"
26#include <QtCore/q26numeric.h>
29# define __has_extension(X) 0
32#if !defined(Q_CC_MSVC) && defined(Q_OS_QNX)
35# define QT_MATH_H_DEFINES_MACROS
63#if defined(QT_MATH_H_DEFINES_MACROS)
64# undef QT_MATH_H_DEFINES_MACROS
87 static_assert(
std::numeric_limits<
double>::has_infinity,
88 "platform has no definition for infinity for type double");
89 return std::numeric_limits<
double>::infinity();
92#if QT_CONFIG(signaling_nan)
93constexpr Q_DECL_CONST_FUNCTION
static inline double qt_snan()
noexcept
95 static_assert(std::numeric_limits<
double>::has_signaling_NaN,
96 "platform has no definition for signaling NaN for type double");
97 return std::numeric_limits<
double>::signaling_NaN();
104 static_assert(
std::numeric_limits<
double>::has_quiet_NaN,
105 "platform has no definition for quiet NaN for type double");
106 return std::numeric_limits<
double>::quiet_NaN();
111 return qnumeric_std_wrapper::isinf(d);
116 return qnumeric_std_wrapper::isnan(d);
121 return qnumeric_std_wrapper::isfinite(d);
126 return qnumeric_std_wrapper::fpclassify(d);
131 return qnumeric_std_wrapper::isinf(f);
136 return qnumeric_std_wrapper::isnan(f);
141 return qnumeric_std_wrapper::isfinite(f);
146 return qnumeric_std_wrapper::fpclassify(f);
152
153
154
155
156
157
158
159
160
161
162
163template <
typename T>
static inline std::enable_if_t<std::is_integral_v<T>,
bool>
164convertDoubleTo(
double v, T *value,
bool allow_precision_upgrade =
true)
166 static_assert(
std::is_integral_v<T>);
167 constexpr bool TypeIsLarger =
std::numeric_limits<T>::digits >
std::numeric_limits<
double>::digits;
169 if constexpr (TypeIsLarger) {
170 using S = std::make_signed_t<T>;
171 constexpr S max_mantissa = S(1) <<
std::numeric_limits<
double>::digits;
175 if (!allow_precision_upgrade && !(v <=
double(max_mantissa) && v >=
double(-max_mantissa - 1)))
179 constexpr T Tmin = (
std::numeric_limits<T>::min)();
180 constexpr T Tmax = (
std::numeric_limits<T>::max)();
192#if defined(Q_PROCESSOR_X86_64) && defined(__SSE2__
)
201 if (std::numeric_limits<T>::is_signed) {
202 __m128d mv = _mm_set_sd(v);
206 *value = T(_mm_cvtt_roundsd_i64(mv, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
208 *value = _mm_cvtt_roundsd_i32(mv, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
210 *value =
sizeof(T) > 4 ? T(_mm_cvttsd_si64(mv)) : _mm_cvttsd_si32(mv);
215 if (*value == Tmin && !_mm_ucomieq_sd(mv, _mm_set_sd(Tmin))) {
224 __m128d mi = _mm_setzero_pd();
225 mi =
sizeof(T) > 4 ? _mm_cvtsi64_sd(mv, *value) : _mm_cvtsi32_sd(mv, *value);
226 return _mm_ucomieq_sd(mv, mi);
230 if (!std::numeric_limits<T>::is_signed) {
240 __m128d mv = _mm_set_sd(v);
244 *value = T(_mm_cvtt_roundsd_u64(mv, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
246 *value = _mm_cvtt_roundsd_u32(mv, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
248 if (*value == Tmax) {
251 if (TypeIsLarger || _mm_ucomieq_sd(mv, _mm_set_sd(
double(Tmax))))
256 __m128d mi = _mm_setzero_pd();
257 mi =
sizeof(T) > 4 ? _mm_cvtu64_sd(mv, *value) : _mm_cvtu32_sd(mv, *value);
258 return _mm_ucomieq_sd(mv, mi);
264 if (
std::numeric_limits<T>::is_signed) {
265 supremum = -1.0 * Tmin;
270 using ST =
typename std::make_signed<T>::type;
271 supremum = -2.0 * (
std::numeric_limits<ST>::min)();
283QT_WARNING_DISABLE_FLOAT_COMPARE
290template <
typename T>
static
291std::enable_if_t<std::is_floating_point_v<T> || std::is_same_v<T, qfloat16>,
bool>
292convertDoubleTo(
double v, T *value,
bool allow_precision_upgrade =
true)
294 Q_UNUSED(allow_precision_upgrade);
295 constexpr T Huge =
std::numeric_limits<T>::infinity();
297 if constexpr (
std::numeric_limits<
double>::max_exponent <=
298 std::numeric_limits<T>::max_exponent) {
304#if defined(__SSE2__
) && (defined(Q_CC_GNU) || __has_extension(gnu_asm))
311 unsigned csr = _MM_MASK_MASK;
312 auto sse_check_result = [&](
auto result) {
313 if ((csr & (_MM_EXCEPT_UNDERFLOW | _MM_EXCEPT_OVERFLOW)) == 0)
315 if (csr & _MM_EXCEPT_OVERFLOW)
330 if constexpr (
std::is_same_v<T,
float>) {
332 asm (
"vldmxcsr %[csr]\n\t"
333 "vcvtsd2ss %[in], %[in], %[out]\n\t"
335 : [csr]
"+m" (csr), [out]
"=v" (*value) : [in]
"v" (v));
337 asm (
"ldmxcsr %[csr]\n\t"
338 "cvtsd2ss %[in], %[out]\n\t"
340 : [csr]
"+m" (csr), [out]
"=v" (*value) : [in]
"v" (v));
342 return sse_check_result(*value);
345# if defined(__F16C__) || defined(__AVX512FP16__)
346 if constexpr (
sizeof(T) == 2 && std::numeric_limits<T>::max_exponent == 16) {
348 auto doConvert = [&](
auto *out) {
349 asm (
"vldmxcsr %[csr]\n\t"
350# ifdef __AVX512FP16__
352 "vcvtsd2sh %[in], %[in], %[out]\n\t"
354 "vcvtsd2ss %[in], %[in], %[out]\n\t"
355 "vcvtps2ph %[rc], %[out], %[out]\n\t"
358 : [csr]
"+m" (csr), [out]
"=v" (*out)
359 : [in]
"v" (v), [rc]
"i" (_MM_FROUND_CUR_DIRECTION)
361 return sse_check_result(out);
364 if constexpr (std::is_same_v<T, qfloat16> && !std::is_void_v<
typename T::NativeType>) {
365 typename T::NativeType tmp;
366 bool b = doConvert(&tmp);
372 return doConvert(value);
379 if (!qt_is_finite(v) && std::numeric_limits<T>::has_infinity) {
387 if (
std::fabs(v) >
double{(
std::numeric_limits<T>::max)()}) {
388 *value = v < 0 ? -Huge : Huge;
393 if (v != 0 && *value == 0) {
400template <
typename T>
inline bool add_overflow(T v1, T v2, T *r) {
return qAddOverflow(v1, v2, r); }
401template <
typename T>
inline bool sub_overflow(T v1, T v2, T *r) {
return qSubOverflow(v1, v2, r); }
402template <
typename T>
inline bool mul_overflow(T v1, T v2, T *r) {
return qMulOverflow(v1, v2, r); }
404template <
typename T, T V2>
bool add_overflow(T v1, std::integral_constant<T, V2>, T *r)
406 return qAddOverflow<T, V2>(v1, std::integral_constant<T, V2>{}, r);
409template <
auto V2,
typename T>
bool add_overflow(T v1, T *r)
411 return qAddOverflow<V2, T>(v1, r);
414template <
typename T, T V2>
bool sub_overflow(T v1, std::integral_constant<T, V2>, T *r)
416 return qSubOverflow<T, V2>(v1, std::integral_constant<T, V2>{}, r);
419template <
auto V2,
typename T>
bool sub_overflow(T v1, T *r)
421 return qSubOverflow<V2, T>(v1, r);
424template <
typename T, T V2>
bool mul_overflow(T v1, std::integral_constant<T, V2>, T *r)
426 return qMulOverflow<T, V2>(v1, std::integral_constant<T, V2>{}, r);
429template <
auto V2,
typename T>
bool mul_overflow(T v1, T *r)
431 return qMulOverflow<V2, T>(v1, r);
436template <
typename To,
typename From>
439 return q26::saturate_cast<To>(x);
\keyword 16-bit Floating Point Support\inmodule QtCore \inheaderfile QFloat16
constexpr const T & min(const T &a, const T &b)
constexpr bool HasLargerInt
constexpr int qSaturateRound(FP value)
constexpr std::enable_if_t<(std::is_unsigned_v< T >||std::is_signed_v< T >), bool > qMulOverflowGeneric(T v1, T v2, T *r)
constexpr auto qUnsignedAbs(T t)
constexpr std::enable_if_t< std::is_unsigned_v< T >, bool > qAddOverflowGeneric(T v1, T v2, T *r)
constexpr std::enable_if_t< std::is_same_v< T, decltype(+T{})>, bool > qMulOverflowWideMultiplication(T v1, T v2, T *r)
constexpr Result qCheckedFPConversionToInteger(FP value)
static Q_DECL_CONST_FUNCTION bool isinf(double d)
static Q_DECL_CONST_FUNCTION bool isnan(float f)
static Q_DECL_CONST_FUNCTION bool isinf(float f)
static Q_DECL_CONST_FUNCTION int fpclassify(float f)
static Q_DECL_CONST_FUNCTION int fpclassify(double d)
static Q_DECL_CONST_FUNCTION bool isfinite(double d)
static Q_DECL_CONST_FUNCTION bool isnan(double d)
static Q_DECL_CONST_FUNCTION bool isfinite(float f)
static quint64 d2i(double d)
Q_CORE_EXPORT int qFpClassify(float val)
Q_CORE_EXPORT int qFpClassify(double val)
static quint32 f2i(float f)
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(float f)
constexpr T qAbs(const T &t)
constexpr std::enable_if< std::is_integral< T >::value, bool >::type qIsFinite(T)
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(double d)
constexpr bool qSubOverflow(T v1, T *r)
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qInf()
constexpr bool qMulOverflow(T v1, T *r)
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(float f)
constexpr bool qFuzzyIsNull(double d) noexcept
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(double d)
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(float f)
constexpr bool qFuzzyCompare(float p1, float p2) noexcept
constexpr bool qSubOverflow(T v1, std::integral_constant< T, V2 >, T *r)
constexpr bool qAddOverflow(T v1, T *r)
constexpr std::enable_if< std::is_integral< T >::value, bool >::type qIsNaN(T)
constexpr std::enable_if_t< std::is_unsigned_v< T >||std::is_signed_v< T >, bool > qMulOverflow(T v1, T v2, T *r)
constexpr qint64 qRound64(double d)
constexpr int qRound(float f)
constexpr int qRound(double d)
constexpr bool qIsNull(float f) noexcept
constexpr bool qFuzzyIsNull(float f) noexcept
constexpr std::enable_if_t< std::is_unsigned_v< T >, bool > qSubOverflow(T v1, T v2, T *r)
constexpr bool qFuzzyCompare(double p1, double p2) noexcept
constexpr qint64 qRound64(float f)
constexpr bool qMulOverflow(T v1, std::integral_constant< T, V2 >, T *r)
QT_WARNING_POP int qIntCast(double f)
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qQNaN()
constexpr std::enable_if_t< std::is_unsigned_v< T >, bool > qAddOverflow(T v1, T v2, T *r)
constexpr bool qAddOverflow(T v1, std::integral_constant< T, V2 >, T *r)
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(double d)
QT_WARNING_PUSH QT_WARNING_DISABLE_FLOAT_COMPARE constexpr bool qIsNull(double d) noexcept
static constexpr auto qt_saturate(From x)
static Q_DECL_CONST_FUNCTION bool qt_is_nan(double d)
#define __has_extension(X)
static Q_DECL_CONST_FUNCTION int qt_fpclassify(float f)
constexpr static Q_DECL_CONST_FUNCTION double qt_qnan() noexcept
constexpr static Q_DECL_CONST_FUNCTION double qt_inf() noexcept
static Q_DECL_CONST_FUNCTION int qt_fpclassify(double d)
static Q_DECL_CONST_FUNCTION bool qt_is_inf(double d)
static Q_DECL_CONST_FUNCTION bool qt_is_finite(double d)
static Q_DECL_CONST_FUNCTION bool qt_is_finite(float f)
static Q_DECL_CONST_FUNCTION bool qt_is_nan(float f)
static Q_DECL_CONST_FUNCTION bool qt_is_inf(float f)