Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qnumeric_p.h
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// Copyright (C) 2021 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6#ifndef QNUMERIC_P_H
7#define QNUMERIC_P_H
8
9//
10// W A R N I N G
11// -------------
12//
13// This file is not part of the Qt API. It exists purely as an
14// implementation detail. This header file may change from version to
15// version without notice, or even be removed.
16//
17// We mean it.
18//
19
20#include "QtCore/private/qglobal_p.h"
21#include "QtCore/qnumeric.h"
22#include "QtCore/qsimd.h"
23#include <cmath>
24#include <limits>
25#include <type_traits>
26
27#include <QtCore/q26numeric.h> // temporarily, for saturate_cast
28
29#ifndef __has_extension
30# define __has_extension(X) 0
31#endif
32
33#if !defined(Q_CC_MSVC) && defined(Q_OS_QNX)
34# include <math.h>
35# ifdef isnan
36# define QT_MATH_H_DEFINES_MACROS
38namespace qnumeric_std_wrapper {
39// the 'using namespace std' below is cases where the stdlib already put the math.h functions in the std namespace and undefined the macros.
40Q_DECL_CONST_FUNCTION static inline bool math_h_isnan(double d) { using namespace std; return isnan(d); }
41Q_DECL_CONST_FUNCTION static inline bool math_h_isinf(double d) { using namespace std; return isinf(d); }
42Q_DECL_CONST_FUNCTION static inline bool math_h_isfinite(double d) { using namespace std; return isfinite(d); }
43Q_DECL_CONST_FUNCTION static inline int math_h_fpclassify(double d) { using namespace std; return fpclassify(d); }
44Q_DECL_CONST_FUNCTION static inline bool math_h_isnan(float f) { using namespace std; return isnan(f); }
45Q_DECL_CONST_FUNCTION static inline bool math_h_isinf(float f) { using namespace std; return isinf(f); }
46Q_DECL_CONST_FUNCTION static inline bool math_h_isfinite(float f) { using namespace std; return isfinite(f); }
47Q_DECL_CONST_FUNCTION static inline int math_h_fpclassify(float f) { using namespace std; return fpclassify(f); }
48}
50// These macros from math.h conflict with the real functions in the std namespace.
51# undef signbit
52# undef isnan
53# undef isinf
54# undef isfinite
55# undef fpclassify
56# endif // defined(isnan)
57#endif
58
60
61class qfloat16;
62
64#if defined(QT_MATH_H_DEFINES_MACROS)
65# undef QT_MATH_H_DEFINES_MACROS
66Q_DECL_CONST_FUNCTION static inline bool isnan(double d) { return math_h_isnan(d); }
67Q_DECL_CONST_FUNCTION static inline bool isinf(double d) { return math_h_isinf(d); }
68Q_DECL_CONST_FUNCTION static inline bool isfinite(double d) { return math_h_isfinite(d); }
69Q_DECL_CONST_FUNCTION static inline int fpclassify(double d) { return math_h_fpclassify(d); }
70Q_DECL_CONST_FUNCTION static inline bool isnan(float f) { return math_h_isnan(f); }
71Q_DECL_CONST_FUNCTION static inline bool isinf(float f) { return math_h_isinf(f); }
72Q_DECL_CONST_FUNCTION static inline bool isfinite(float f) { return math_h_isfinite(f); }
73Q_DECL_CONST_FUNCTION static inline int fpclassify(float f) { return math_h_fpclassify(f); }
74#else
75Q_DECL_CONST_FUNCTION static inline bool isnan(double d) { return std::isnan(d); }
76Q_DECL_CONST_FUNCTION static inline bool isinf(double d) { return std::isinf(d); }
77Q_DECL_CONST_FUNCTION static inline bool isfinite(double d) { return std::isfinite(d); }
78Q_DECL_CONST_FUNCTION static inline int fpclassify(double d) { return std::fpclassify(d); }
79Q_DECL_CONST_FUNCTION static inline bool isnan(float f) { return std::isnan(f); }
80Q_DECL_CONST_FUNCTION static inline bool isinf(float f) { return std::isinf(f); }
81Q_DECL_CONST_FUNCTION static inline bool isfinite(float f) { return std::isfinite(f); }
82Q_DECL_CONST_FUNCTION static inline int fpclassify(float f) { return std::fpclassify(f); }
83#endif
84}
85
86constexpr Q_DECL_CONST_FUNCTION static inline double qt_inf() noexcept
87{
88 static_assert(std::numeric_limits<double>::has_infinity,
89 "platform has no definition for infinity for type double");
90 return std::numeric_limits<double>::infinity();
91}
92
93#if QT_CONFIG(signaling_nan)
94constexpr Q_DECL_CONST_FUNCTION static inline double qt_snan() noexcept
95{
96 static_assert(std::numeric_limits<double>::has_signaling_NaN,
97 "platform has no definition for signaling NaN for type double");
98 return std::numeric_limits<double>::signaling_NaN();
99}
100#endif
101
102// Quiet NaN
103constexpr Q_DECL_CONST_FUNCTION static inline double qt_qnan() noexcept
104{
105 static_assert(std::numeric_limits<double>::has_quiet_NaN,
106 "platform has no definition for quiet NaN for type double");
107 return std::numeric_limits<double>::quiet_NaN();
108}
109
110Q_DECL_CONST_FUNCTION static inline bool qt_is_inf(double d)
111{
112 return qnumeric_std_wrapper::isinf(d);
113}
114
115Q_DECL_CONST_FUNCTION static inline bool qt_is_nan(double d)
116{
117 return qnumeric_std_wrapper::isnan(d);
118}
119
120Q_DECL_CONST_FUNCTION static inline bool qt_is_finite(double d)
121{
122 return qnumeric_std_wrapper::isfinite(d);
123}
124
125Q_DECL_CONST_FUNCTION static inline int qt_fpclassify(double d)
126{
127 return qnumeric_std_wrapper::fpclassify(d);
128}
129
130Q_DECL_CONST_FUNCTION static inline bool qt_is_inf(float f)
131{
132 return qnumeric_std_wrapper::isinf(f);
133}
134
135Q_DECL_CONST_FUNCTION static inline bool qt_is_nan(float f)
136{
137 return qnumeric_std_wrapper::isnan(f);
138}
139
140Q_DECL_CONST_FUNCTION static inline bool qt_is_finite(float f)
141{
142 return qnumeric_std_wrapper::isfinite(f);
143}
144
145Q_DECL_CONST_FUNCTION static inline int qt_fpclassify(float f)
146{
147 return qnumeric_std_wrapper::fpclassify(f);
148}
149
150#ifndef Q_QDOC
151namespace {
152/*!
153 Returns true if the double \a v can be converted to type \c T, false if
154 it's out of range. If the conversion is successful, the converted value is
155 stored in \a value; if it was not successful, \a value will contain the
156 minimum or maximum of T, depending on the sign of \a d. If \c T is
157 unsigned, then \a value contains the absolute value of \a v. If \c T is \c
158 float, an underflow is also signalled by returning false and setting \a
159 value to zero.
160
161 This function works for v containing infinities, but not NaN. It's the
162 caller's responsibility to exclude that possibility before calling it.
163*/
164template <typename T> static inline std::enable_if_t<std::is_integral_v<T>, bool>
165convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true)
166{
167 static_assert(std::is_integral_v<T>);
168 constexpr bool TypeIsLarger = std::numeric_limits<T>::digits > std::numeric_limits<double>::digits;
169
170 if constexpr (TypeIsLarger) {
171 using S = std::make_signed_t<T>;
172 constexpr S max_mantissa = S(1) << std::numeric_limits<double>::digits;
173 // T has more bits than double's mantissa, so don't allow "upgrading"
174 // to T (makes it look like the number had more precision than really
175 // was transmitted)
176 if (!allow_precision_upgrade && !(v <= double(max_mantissa) && v >= double(-max_mantissa - 1)))
177 return false;
178 }
179
180 constexpr T Tmin = (std::numeric_limits<T>::min)();
181 constexpr T Tmax = (std::numeric_limits<T>::max)();
182
183 // The [conv.fpint] (7.10 Floating-integral conversions) section of the C++
184 // standard says only exact conversions are guaranteed. Converting
185 // integrals to floating-point with loss of precision has implementation-
186 // defined behavior whether the next higher or next lower is returned;
187 // converting FP to integral is UB if it can't be represented.
188 //
189 // That means we can't write UINT64_MAX+1. Writing ldexp(1, 64) would be
190 // correct, but Clang, ICC and MSVC don't realize that it's a constant and
191 // the math call stays in the compiled code.
192
193#if defined(Q_PROCESSOR_X86_64) && defined(__SSE2__)
194 // Of course, UB doesn't apply if we use intrinsics, in which case we are
195 // allowed to dpeend on exactly the processor's behavior. This
196 // implementation uses the truncating conversions from Scalar Double to
197 // integral types (CVTTSD2SI and VCVTTSD2USI), which is documented to
198 // return the "indefinite integer value" if the range of the target type is
199 // exceeded. (only implemented for x86-64 to avoid having to deal with the
200 // non-existence of the 64-bit intrinsics on i386)
201
202 if (std::numeric_limits<T>::is_signed) {
203 __m128d mv = _mm_set_sd(v);
204# ifdef __AVX512F__
205 // use explicit round control and suppress exceptions
206 if (sizeof(T) > 4)
207 *value = T(_mm_cvtt_roundsd_i64(mv, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
208 else
209 *value = _mm_cvtt_roundsd_i32(mv, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
210# else
211 *value = sizeof(T) > 4 ? T(_mm_cvttsd_si64(mv)) : _mm_cvttsd_si32(mv);
212# endif
213
214 // if *value is the "indefinite integer value", check if the original
215 // variable \a v is the same value (Tmin is an exact representation)
216 if (*value == Tmin && !_mm_ucomieq_sd(mv, _mm_set_sd(Tmin))) {
217 // v != Tmin, so it was out of range
218 if (v > 0)
219 *value = Tmax;
220 return false;
221 }
222
223 // convert the integer back to double and compare for equality with v,
224 // to determine if we've lost any precision
225 __m128d mi = _mm_setzero_pd();
226 mi = sizeof(T) > 4 ? _mm_cvtsi64_sd(mv, *value) : _mm_cvtsi32_sd(mv, *value);
227 return _mm_ucomieq_sd(mv, mi);
228 }
229
230# ifdef __AVX512F__
231 if (!std::numeric_limits<T>::is_signed) {
232 // Same thing as above, but this function operates on absolute values
233 // and the "indefinite integer value" for the 64-bit unsigned
234 // conversion (Tmax) is not representable in double, so it can never be
235 // the result of an in-range conversion. This is implemented for AVX512
236 // and later because of the unsigned conversion instruction. Converting
237 // to unsigned without losing an extra bit of precision prior to AVX512
238 // is left to the compiler below.
239
240 v = fabs(v);
241 __m128d mv = _mm_set_sd(v);
242
243 // use explicit round control and suppress exceptions
244 if (sizeof(T) > 4)
245 *value = T(_mm_cvtt_roundsd_u64(mv, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
246 else
247 *value = _mm_cvtt_roundsd_u32(mv, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
248
249 if (*value == Tmax) {
250 // no double can have an exact value of quint64(-1), but they can
251 // quint32(-1), so we need to compare for that
252 if (TypeIsLarger || _mm_ucomieq_sd(mv, _mm_set_sd(double(Tmax))))
253 return false;
254 }
255
256 // return true if it was an exact conversion
257 __m128d mi = _mm_setzero_pd();
258 mi = sizeof(T) > 4 ? _mm_cvtu64_sd(mv, *value) : _mm_cvtu32_sd(mv, *value);
259 return _mm_ucomieq_sd(mv, mi);
260 }
261# endif
262#endif
263
264 double supremum;
265 if (std::numeric_limits<T>::is_signed) {
266 supremum = -1.0 * Tmin; // -1 * (-2^63) = 2^63, exact (for T = qint64)
267 *value = Tmin;
268 if (v < Tmin)
269 return false;
270 } else {
271 using ST = typename std::make_signed<T>::type;
272 supremum = -2.0 * (std::numeric_limits<ST>::min)(); // -2 * (-2^63) = 2^64, exact (for T = quint64)
273 v = fabs(v);
274 }
275
276 *value = Tmax;
277 if (v >= supremum)
278 return false;
279
280 // Now we can convert, these two conversions cannot be UB
281 *value = T(v);
282
283QT_WARNING_PUSH
284QT_WARNING_DISABLE_FLOAT_COMPARE
285
286 return *value == v;
287
288QT_WARNING_POP
289}
290
291template <typename T> static
292std::enable_if_t<std::is_floating_point_v<T> || std::is_same_v<T, qfloat16>, bool>
293convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true)
294{
295 Q_UNUSED(allow_precision_upgrade);
296 constexpr T Huge = std::numeric_limits<T>::infinity();
297
298 if constexpr (std::numeric_limits<double>::max_exponent <=
299 std::numeric_limits<T>::max_exponent) {
300 // no UB can happen
301 *value = T(v);
302 return true;
303 }
304
305#if defined(__SSE2__) && (defined(Q_CC_GNU) || __has_extension(gnu_asm))
306 // The x86 CVTSD2SH instruction from SSE2 does what we want:
307 // - converts out-of-range doubles to ±infinity and sets #O
308 // - converts underflows to zero and sets #U
309 // We need to clear any previously-stored exceptions from it before the
310 // operation (3-cycle cost) and obtain the new state afterwards (1 cycle).
311
312 unsigned csr = _MM_MASK_MASK; // clear stored exception indicators
313 auto sse_check_result = [&](auto result) {
314 if ((csr & (_MM_EXCEPT_UNDERFLOW | _MM_EXCEPT_OVERFLOW)) == 0)
315 return true;
316 if (csr & _MM_EXCEPT_OVERFLOW)
317 return false;
318
319 // According to IEEE 754[1], #U is also set when the result is tiny and
320 // inexact, but still non-zero, so detect that (this won't generate
321 // good code for types without hardware support).
322 // [1] https://en.wikipedia.org/wiki/Floating-point_arithmetic#Exception_handling
323 return result != 0;
324 };
325
326 // Written directly in assembly because both Clang and GCC have been
327 // observed to reorder the STMXCSR instruction above the conversion
328 // operation. MSVC generates horrid code when using the intrinsics anyway,
329 // so it's not a loss.
330 // See https://github.com/llvm/llvm-project/issues/83661.
331 if constexpr (std::is_same_v<T, float>) {
332# ifdef __AVX__
333 asm ("vldmxcsr %[csr]\n\t"
334 "vcvtsd2ss %[in], %[in], %[out]\n\t"
335 "vstmxcsr %[csr]"
336 : [csr] "+m" (csr), [out] "=v" (*value) : [in] "v" (v));
337# else
338 asm ("ldmxcsr %[csr]\n\t"
339 "cvtsd2ss %[in], %[out]\n\t"
340 "stmxcsr %[csr]"
341 : [csr] "+m" (csr), [out] "=v" (*value) : [in] "v" (v));
342# endif
343 return sse_check_result(*value);
344 }
345
346# if defined(__F16C__) || defined(__AVX512FP16__)
347 if constexpr (sizeof(T) == 2 && std::numeric_limits<T>::max_exponent == 16) {
348 // qfloat16 or std::float16_t, but not std::bfloat16_t or std::bfloat8_t
349 auto doConvert = [&](auto *out) {
350 asm ("vldmxcsr %[csr]\n\t"
351# ifdef __AVX512FP16__
352 // AVX512FP16 & AVX10 have an instruction for this
353 "vcvtsd2sh %[in], %[in], %[out]\n\t"
354# else
355 "vcvtsd2ss %[in], %[in], %[out]\n\t" // sets DEST[MAXVL-1:128] := 0
356 "vcvtps2ph %[rc], %[out], %[out]\n\t"
357# endif
358 "vstmxcsr %[csr]"
359 : [csr] "+m" (csr), [out] "=v" (*out)
360 : [in] "v" (v), [rc] "i" (_MM_FROUND_CUR_DIRECTION)
361 );
362 return sse_check_result(out);
363 };
364
365 if constexpr (std::is_same_v<T, qfloat16> && !std::is_void_v<typename T::NativeType>) {
366 typename T::NativeType tmp;
367 bool b = doConvert(&tmp);
368 *value = tmp;
369 return b;
370 } else {
371# ifndef Q_CC_CLANG
372 // Clang can only implement this if it has a native FP16 type
373 return doConvert(value);
374# endif
375 }
376 }
377# endif
378#endif // __SSE2__ && inline assembly
379
380 if (!qt_is_finite(v) && std::numeric_limits<T>::has_infinity) {
381 // infinity (or NaN)
382 *value = T(v);
383 return true;
384 }
385
386 // Check for in-range value to ensure the conversion is not UB (see the
387 // comment above for Standard language).
388 if (std::fabs(v) > double{(std::numeric_limits<T>::max)()}) {
389 *value = v < 0 ? -Huge : Huge;
390 return false;
391 }
392
393 *value = T(v);
394 if (v != 0 && *value == 0) {
395 // Underflow through loss of precision
396 return false;
397 }
398 return true;
399}
400
401template <typename T> inline bool add_overflow(T v1, T v2, T *r) { return qAddOverflow(v1, v2, r); }
402template <typename T> inline bool sub_overflow(T v1, T v2, T *r) { return qSubOverflow(v1, v2, r); }
403template <typename T> inline bool mul_overflow(T v1, T v2, T *r) { return qMulOverflow(v1, v2, r); }
404
405template <typename T, T V2> bool add_overflow(T v1, std::integral_constant<T, V2>, T *r)
406{
407 return qAddOverflow<T, V2>(v1, std::integral_constant<T, V2>{}, r);
408}
409
410template <auto V2, typename T> bool add_overflow(T v1, T *r)
411{
412 return qAddOverflow<V2, T>(v1, r);
413}
414
415template <typename T, T V2> bool sub_overflow(T v1, std::integral_constant<T, V2>, T *r)
416{
417 return qSubOverflow<T, V2>(v1, std::integral_constant<T, V2>{}, r);
418}
419
420template <auto V2, typename T> bool sub_overflow(T v1, T *r)
421{
422 return qSubOverflow<V2, T>(v1, r);
423}
424
425template <typename T, T V2> bool mul_overflow(T v1, std::integral_constant<T, V2>, T *r)
426{
427 return qMulOverflow<T, V2>(v1, std::integral_constant<T, V2>{}, r);
428}
429
430template <auto V2, typename T> bool mul_overflow(T v1, T *r)
431{
432 return qMulOverflow<V2, T>(v1, r);
433}
434}
435#endif // Q_QDOC
436
437template <typename To, typename From>
438static constexpr auto qt_saturate(From x)
439{
440 return q26::saturate_cast<To>(x);
441}
442
443QT_END_NAMESPACE
444
445#endif // QNUMERIC_P_H
\keyword 16-bit Floating Point Support\inmodule QtCore \inheaderfile QFloat16
Definition qfloat16.h:57
Combined button and popup list for selecting options.
constexpr const T & min(const T &a, const T &b)
Definition qnumeric.h:592
constexpr bool HasLargerInt
Definition qnumeric.h:227
constexpr int qSaturateRound(FP value)
Definition qnumeric.h:557
constexpr std::enable_if_t<(std::is_unsigned_v< T >||std::is_signed_v< T >), bool > qMulOverflowGeneric(T v1, T v2, T *r)
Definition qnumeric.h:234
constexpr auto qUnsignedAbs(T t)
Definition qnumeric.h:494
constexpr std::enable_if_t< std::is_unsigned_v< T >, bool > qAddOverflowGeneric(T v1, T v2, T *r)
Definition qnumeric.h:112
constexpr std::enable_if_t< std::is_same_v< T, decltype(+T{})>, bool > qMulOverflowWideMultiplication(T v1, T v2, T *r)
Definition qnumeric.h:126
constexpr bool fuzzyCompare(const T &lhs, const S &rhs) noexcept
Definition qnumeric.h:641
constexpr Result qCheckedFPConversionToInteger(FP value)
Definition qnumeric.h:504
static Q_DECL_CONST_FUNCTION bool isinf(double d)
Definition qnumeric_p.h:76
static Q_DECL_CONST_FUNCTION bool isnan(float f)
Definition qnumeric_p.h:79
static Q_DECL_CONST_FUNCTION bool isinf(float f)
Definition qnumeric_p.h:80
static Q_DECL_CONST_FUNCTION int fpclassify(float f)
Definition qnumeric_p.h:82
static Q_DECL_CONST_FUNCTION int fpclassify(double d)
Definition qnumeric_p.h:78
static Q_DECL_CONST_FUNCTION bool isfinite(double d)
Definition qnumeric_p.h:77
static Q_DECL_CONST_FUNCTION bool isnan(double d)
Definition qnumeric_p.h:75
static Q_DECL_CONST_FUNCTION bool isfinite(float f)
Definition qnumeric_p.h:81
#define __has_builtin(x)
static quint64 d2i(double d)
Definition qnumeric.cpp:181
Q_CORE_EXPORT int qFpClassify(float val)
Definition qnumeric.cpp:102
Q_CORE_EXPORT int qFpClassify(double val)
Definition qnumeric.cpp:101
static quint32 f2i(float f)
Definition qnumeric.cpp:108
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(float f)
int qIntCast(double f)
Definition qnumeric.h:651
constexpr T qAbs(const T &t)
Definition qnumeric.h:484
constexpr std::enable_if< std::is_integral< T >::value, bool >::type qIsFinite(T)
Definition qnumeric.h:61
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(double d)
constexpr bool qSubOverflow(T v1, T *r)
Definition qnumeric.h:422
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qInf()
constexpr bool qMulOverflow(T v1, T *r)
Definition qnumeric.h:476
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(float f)
constexpr bool qFuzzyIsNull(double d) noexcept
Definition qnumeric.h:605
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
Definition qnumeric.h:600
constexpr bool qSubOverflow(T v1, std::integral_constant< T, V2 >, T *r)
Definition qnumeric.h:417
constexpr bool qAddOverflow(T v1, T *r)
Definition qnumeric.h:412
constexpr std::enable_if< std::is_integral< T >::value, bool >::type qIsNaN(T)
Definition qnumeric.h:58
constexpr std::enable_if_t< std::is_unsigned_v< T >||std::is_signed_v< T >, bool > qMulOverflow(T v1, T v2, T *r)
Definition qnumeric.h:360
constexpr qint64 qRound64(double d)
Definition qnumeric.h:580
constexpr int qRound(float f)
Definition qnumeric.h:575
int qIntCast(float f)
Definition qnumeric.h:652
constexpr int qRound(double d)
Definition qnumeric.h:570
constexpr bool qIsNull(float f) noexcept
Definition qnumeric.h:623
constexpr bool qFuzzyIsNull(float f) noexcept
Definition qnumeric.h:610
constexpr std::enable_if_t< std::is_unsigned_v< T >, bool > qSubOverflow(T v1, T v2, T *r)
Definition qnumeric.h:325
constexpr bool qFuzzyCompare(double p1, double p2) noexcept
Definition qnumeric.h:595
constexpr qint64 qRound64(float f)
Definition qnumeric.h:585
constexpr bool qMulOverflow(T v1, std::integral_constant< T, V2 >, T *r)
Definition qnumeric.h:427
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)
Definition qnumeric.h:264
constexpr bool qAddOverflow(T v1, std::integral_constant< T, V2 >, T *r)
Definition qnumeric.h:407
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
Definition qnumeric.h:618
static constexpr auto qt_saturate(From x)
Definition qnumeric_p.h:438
static Q_DECL_CONST_FUNCTION bool qt_is_nan(double d)
Definition qnumeric_p.h:115
#define __has_extension(X)
Definition qnumeric_p.h:30
static Q_DECL_CONST_FUNCTION int qt_fpclassify(float f)
Definition qnumeric_p.h:145
constexpr static Q_DECL_CONST_FUNCTION double qt_qnan() noexcept
Definition qnumeric_p.h:103
constexpr static Q_DECL_CONST_FUNCTION double qt_inf() noexcept
Definition qnumeric_p.h:86
static Q_DECL_CONST_FUNCTION int qt_fpclassify(double d)
Definition qnumeric_p.h:125
static Q_DECL_CONST_FUNCTION bool qt_is_inf(double d)
Definition qnumeric_p.h:110
static Q_DECL_CONST_FUNCTION bool qt_is_finite(double d)
Definition qnumeric_p.h:120
static Q_DECL_CONST_FUNCTION bool qt_is_finite(float f)
Definition qnumeric_p.h:140
static Q_DECL_CONST_FUNCTION bool qt_is_nan(float f)
Definition qnumeric_p.h:135
static Q_DECL_CONST_FUNCTION bool qt_is_inf(float f)
Definition qnumeric_p.h:130