Warning, file /include/QtCore/qnumeric.h was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004 #ifndef QNUMERIC_H
0005 #define QNUMERIC_H
0006
0007 #if 0
0008 #pragma qt_class(QtNumeric)
0009 #endif
0010
0011 #include <QtCore/qtconfigmacros.h>
0012 #include <QtCore/qtcoreexports.h>
0013 #include <QtCore/qtypes.h>
0014
0015 #include <cmath>
0016 #include <limits>
0017 #include <type_traits>
0018
0019
0020
0021 #ifdef min
0022 # undef min
0023 # undef max
0024 #endif
0025
0026 #if defined(Q_CC_MSVC)
0027 # include <intrin.h>
0028 # include <float.h>
0029 # if defined(Q_PROCESSOR_X86_64) || defined(Q_PROCESSOR_ARM_64)
0030 # define Q_INTRINSIC_MUL_OVERFLOW64
0031 # define Q_UMULH(v1, v2) __umulh(v1, v2);
0032 # define Q_SMULH(v1, v2) __mulh(v1, v2);
0033 # pragma intrinsic(__umulh)
0034 # pragma intrinsic(__mulh)
0035 # endif
0036 #endif
0037
0038 # if defined(Q_OS_INTEGRITY) && defined(Q_PROCESSOR_ARM_64)
0039 # include <arm64_ghs.h>
0040 # define Q_INTRINSIC_MUL_OVERFLOW64
0041 # define Q_UMULH(v1, v2) __MULUH64(v1, v2);
0042 # define Q_SMULH(v1, v2) __MULSH64(v1, v2);
0043 #endif
0044
0045 QT_BEGIN_NAMESPACE
0046
0047
0048 template <typename T>
0049 constexpr typename std::enable_if<std::is_integral<T>::value, bool>::type
0050 qIsInf(T) { return false; }
0051 template <typename T>
0052 constexpr typename std::enable_if<std::is_integral<T>::value, bool>::type
0053 qIsNaN(T) { return false; }
0054 template <typename T>
0055 constexpr typename std::enable_if<std::is_integral<T>::value, bool>::type
0056 qIsFinite(T) { return true; }
0057
0058
0059 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(double d);
0060 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(double d);
0061 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(double d);
0062 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION int qFpClassify(double val);
0063 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(float f);
0064 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(float f);
0065 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(float f);
0066 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION int qFpClassify(float val);
0067
0068 #if QT_CONFIG(signaling_nan)
0069 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qSNaN();
0070 #endif
0071 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qQNaN();
0072 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qInf();
0073
0074 Q_CORE_EXPORT quint32 qFloatDistance(float a, float b);
0075 Q_CORE_EXPORT quint64 qFloatDistance(double a, double b);
0076
0077 #define Q_INFINITY (QT_PREPEND_NAMESPACE(qInf)())
0078 #if QT_CONFIG(signaling_nan)
0079 # define Q_SNAN (QT_PREPEND_NAMESPACE(qSNaN)())
0080 #endif
0081 #define Q_QNAN (QT_PREPEND_NAMESPACE(qQNaN)())
0082
0083
0084
0085
0086
0087
0088 #if (Q_CC_GNU >= 500 || __has_builtin(__builtin_add_overflow)) \
0089 && !(QT_POINTER_SIZE == 4 && defined(Q_CC_CLANG))
0090
0091
0092 #define Q_INTRINSIC_MUL_OVERFLOW64
0093
0094 template <typename T> inline
0095 typename std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool>
0096 qAddOverflow(T v1, T v2, T *r)
0097 { return __builtin_add_overflow(v1, v2, r); }
0098
0099 template <typename T> inline
0100 typename std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool>
0101 qSubOverflow(T v1, T v2, T *r)
0102 { return __builtin_sub_overflow(v1, v2, r); }
0103
0104 template <typename T> inline
0105 typename std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool>
0106 qMulOverflow(T v1, T v2, T *r)
0107 { return __builtin_mul_overflow(v1, v2, r); }
0108
0109 #else
0110
0111
0112 template <typename T> inline typename std::enable_if_t<std::is_unsigned_v<T>, bool>
0113 qAddOverflow(T v1, T v2, T *r)
0114 {
0115
0116 *r = v1 + v2;
0117 return v1 > T(v1 + v2);
0118 }
0119
0120 template <typename T> inline typename std::enable_if_t<std::is_signed_v<T>, bool>
0121 qAddOverflow(T v1, T v2, T *r)
0122 {
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132 using U = typename std::make_unsigned_t<T>;
0133 *r = T(U(v1) + U(v2));
0134
0135
0136 if (std::is_same_v<int32_t, int>) {
0137
0138
0139
0140
0141
0142 return ((v1 ^ *r) & (v2 ^ *r)) < 0;
0143 }
0144
0145 bool s1 = (v1 < 0);
0146 bool s2 = (v2 < 0);
0147 bool sr = (*r < 0);
0148 return s1 != sr && s2 != sr;
0149
0150 }
0151
0152 template <typename T> inline typename std::enable_if_t<std::is_unsigned_v<T>, bool>
0153 qSubOverflow(T v1, T v2, T *r)
0154 {
0155
0156 *r = v1 - v2;
0157 return v1 < v2;
0158 }
0159
0160 template <typename T> inline typename std::enable_if_t<std::is_signed_v<T>, bool>
0161 qSubOverflow(T v1, T v2, T *r)
0162 {
0163
0164
0165
0166
0167 using U = typename std::make_unsigned_t<T>;
0168 *r = T(U(v1) - U(v2));
0169
0170 if (std::is_same_v<int32_t, int>)
0171 return ((v1 ^ *r) & (~v2 ^ *r)) < 0;
0172
0173 bool s1 = (v1 < 0);
0174 bool s2 = !(v2 < 0);
0175 bool sr = (*r < 0);
0176 return s1 != sr && s2 != sr;
0177
0178 }
0179
0180 template <typename T> inline
0181 typename std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool>
0182 qMulOverflow(T v1, T v2, T *r)
0183 {
0184
0185
0186 using LargerInt = QIntegerForSize<sizeof(T) * 2>;
0187 using Larger = typename std::conditional_t<std::is_signed_v<T>,
0188 typename LargerInt::Signed, typename LargerInt::Unsigned>;
0189 Larger lr = Larger(v1) * Larger(v2);
0190 *r = T(lr);
0191 return lr > (std::numeric_limits<T>::max)() || lr < (std::numeric_limits<T>::min)();
0192 }
0193
0194 # if defined(Q_INTRINSIC_MUL_OVERFLOW64)
0195 template <> inline bool qMulOverflow(quint64 v1, quint64 v2, quint64 *r)
0196 {
0197 *r = v1 * v2;
0198 return Q_UMULH(v1, v2);
0199 }
0200 template <> inline bool qMulOverflow(qint64 v1, qint64 v2, qint64 *r)
0201 {
0202
0203
0204
0205
0206
0207
0208 qint64 high = Q_SMULH(v1, v2);
0209 *r = qint64(quint64(v1) * quint64(v2));
0210 return (*r >> 63) != high;
0211 }
0212
0213 # if defined(Q_OS_INTEGRITY) && defined(Q_PROCESSOR_ARM_64)
0214 template <> inline bool qMulOverflow(uint64_t v1, uint64_t v2, uint64_t *r)
0215 {
0216 return qMulOverflow<quint64>(v1,v2,reinterpret_cast<quint64*>(r));
0217 }
0218
0219 template <> inline bool qMulOverflow(int64_t v1, int64_t v2, int64_t *r)
0220 {
0221 return qMulOverflow<qint64>(v1,v2,reinterpret_cast<qint64*>(r));
0222 }
0223 # endif
0224 # endif
0225
0226 # if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86)
0227
0228 template <> inline bool qAddOverflow(unsigned v1, unsigned v2, unsigned *r)
0229 { return _addcarry_u32(0, v1, v2, r); }
0230
0231
0232
0233 template <> inline bool qAddOverflow(quint64 v1, quint64 v2, quint64 *r)
0234 {
0235 # if defined(Q_PROCESSOR_X86_64)
0236 return _addcarry_u64(0, v1, v2, reinterpret_cast<unsigned __int64 *>(r));
0237 # else
0238 uint low, high;
0239 uchar carry = _addcarry_u32(0, unsigned(v1), unsigned(v2), &low);
0240 carry = _addcarry_u32(carry, v1 >> 32, v2 >> 32, &high);
0241 *r = (quint64(high) << 32) | low;
0242 return carry;
0243 # endif
0244 }
0245 # endif
0246 #endif
0247
0248
0249
0250
0251
0252
0253 template <typename T, T V2> bool qAddOverflow(T v1, std::integral_constant<T, V2>, T *r)
0254 {
0255 return qAddOverflow(v1, V2, r);
0256 }
0257
0258 template <auto V2, typename T> bool qAddOverflow(T v1, T *r)
0259 {
0260 return qAddOverflow(v1, std::integral_constant<T, V2>{}, r);
0261 }
0262
0263 template <typename T, T V2> bool qSubOverflow(T v1, std::integral_constant<T, V2>, T *r)
0264 {
0265 return qSubOverflow(v1, V2, r);
0266 }
0267
0268 template <auto V2, typename T> bool qSubOverflow(T v1, T *r)
0269 {
0270 return qSubOverflow(v1, std::integral_constant<T, V2>{}, r);
0271 }
0272
0273 template <typename T, T V2> bool qMulOverflow(T v1, std::integral_constant<T, V2>, T *r)
0274 {
0275
0276
0277
0278
0279 if constexpr (sizeof(T) <= sizeof(qregisteruint)) {
0280 return qMulOverflow(v1, V2, r);
0281
0282 #ifdef Q_INTRINSIC_MUL_OVERFLOW64
0283 } else if constexpr (sizeof(T) <= sizeof(quint64)) {
0284
0285
0286 return qMulOverflow(v1, V2, r);
0287 #endif
0288
0289 } else if constexpr (V2 == 0 || V2 == 1) {
0290
0291 *r = v1 * V2;
0292 return false;
0293 } else if constexpr (V2 == -1) {
0294
0295
0296 if (v1 < 0 && v1 == (std::numeric_limits<T>::min)())
0297 return true;
0298 *r = -v1;
0299 return false;
0300 } else {
0301
0302
0303 constexpr T Highest = (std::numeric_limits<T>::max)() / V2;
0304 constexpr T Lowest = (std::numeric_limits<T>::min)() / V2;
0305 if constexpr (Highest > Lowest) {
0306 if (v1 > Highest || v1 < Lowest)
0307 return true;
0308 } else {
0309
0310 static_assert(V2 < 0);
0311 if (v1 > Lowest || v1 < Highest)
0312 return true;
0313 }
0314
0315 *r = v1 * V2;
0316 return false;
0317 }
0318 }
0319
0320 template <auto V2, typename T> bool qMulOverflow(T v1, T *r)
0321 {
0322 if constexpr (V2 == 2)
0323 return qAddOverflow(v1, v1, r);
0324 return qMulOverflow(v1, std::integral_constant<T, V2>{}, r);
0325 }
0326
0327 template <typename T>
0328 constexpr inline T qAbs(const T &t) { return t >= 0 ? t : -t; }
0329
0330
0331 #if defined(Q_PROCESSOR_ARM_64) && (__has_builtin(__builtin_round) || defined(Q_CC_GNU)) && !defined(Q_CC_CLANG)
0332
0333
0334 constexpr inline int qRound(double d)
0335 { return int(__builtin_round(d)); }
0336 constexpr inline int qRound(float f)
0337 { return int(__builtin_roundf(f)); }
0338 constexpr inline qint64 qRound64(double d)
0339 { return qint64(__builtin_round(d)); }
0340 constexpr inline qint64 qRound64(float f)
0341 { return qint64(__builtin_roundf(f)); }
0342 #elif defined(__SSE2__) && (__has_builtin(__builtin_copysign) || defined(Q_CC_GNU))
0343
0344 constexpr inline int qRound(double d)
0345 { return int(d + __builtin_copysign(0.5, d)); }
0346 constexpr inline int qRound(float f)
0347 { return int(f + __builtin_copysignf(0.5f, f)); }
0348 constexpr inline qint64 qRound64(double d)
0349 { return qint64(d + __builtin_copysign(0.5, d)); }
0350 constexpr inline qint64 qRound64(float f)
0351 { return qint64(f + __builtin_copysignf(0.5f, f)); }
0352 #else
0353 constexpr inline int qRound(double d)
0354 { return d >= 0.0 ? int(d + 0.5) : int(d - 0.5); }
0355 constexpr inline int qRound(float d)
0356 { return d >= 0.0f ? int(d + 0.5f) : int(d - 0.5f); }
0357
0358 constexpr inline qint64 qRound64(double d)
0359 { return d >= 0.0 ? qint64(d + 0.5) : qint64(d - 0.5); }
0360 constexpr inline qint64 qRound64(float d)
0361 { return d >= 0.0f ? qint64(d + 0.5f) : qint64(d - 0.5f); }
0362 #endif
0363
0364 namespace QtPrivate {
0365 template <typename T>
0366 constexpr inline const T &min(const T &a, const T &b) { return (a < b) ? a : b; }
0367 }
0368
0369 [[nodiscard]] constexpr bool qFuzzyCompare(double p1, double p2)
0370 {
0371 return (qAbs(p1 - p2) * 1000000000000. <= QtPrivate::min(qAbs(p1), qAbs(p2)));
0372 }
0373
0374 [[nodiscard]] constexpr bool qFuzzyCompare(float p1, float p2)
0375 {
0376 return (qAbs(p1 - p2) * 100000.f <= QtPrivate::min(qAbs(p1), qAbs(p2)));
0377 }
0378
0379 [[nodiscard]] constexpr bool qFuzzyIsNull(double d)
0380 {
0381 return qAbs(d) <= 0.000000000001;
0382 }
0383
0384 [[nodiscard]] constexpr bool qFuzzyIsNull(float f)
0385 {
0386 return qAbs(f) <= 0.00001f;
0387 }
0388
0389 QT_WARNING_PUSH
0390 QT_WARNING_DISABLE_FLOAT_COMPARE
0391
0392 [[nodiscard]] constexpr bool qIsNull(double d) noexcept
0393 {
0394 return d == 0.0;
0395 }
0396
0397 [[nodiscard]] constexpr bool qIsNull(float f) noexcept
0398 {
0399 return f == 0.0f;
0400 }
0401
0402 QT_WARNING_POP
0403
0404 inline int qIntCast(double f) { return int(f); }
0405 inline int qIntCast(float f) { return int(f); }
0406
0407 QT_END_NAMESPACE
0408
0409 #endif