File indexing completed on 2026-08-05 09:27:31
0001
0002
0003
0004
0005
0006 #ifndef QNUMERIC_H
0007 #define QNUMERIC_H
0008
0009 #if 0
0010 #pragma qt_class(QtNumeric)
0011 #endif
0012
0013 #include <QtCore/qassert.h>
0014 #include <QtCore/qminmax.h>
0015 #include <QtCore/qtconfigmacros.h>
0016 #include <QtCore/qtcoreexports.h>
0017 #include <QtCore/qtypes.h>
0018
0019 #include <cmath>
0020 #include <limits>
0021 #include <QtCore/q20type_traits.h>
0022
0023
0024
0025 #ifdef min
0026 # undef min
0027 # undef max
0028 #endif
0029
0030
0031
0032
0033
0034
0035 #if defined(Q_CC_MSVC) && !defined(Q_NUMERIC_NO_INTRINSICS)
0036 # include <intrin.h>
0037 # include <float.h>
0038 # if defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_X86_64)
0039 # define Q_HAVE_ADDCARRY
0040 # endif
0041 # if defined(Q_PROCESSOR_X86_64) || defined(Q_PROCESSOR_ARM_64)
0042 # define Q_INTRINSIC_MUL_OVERFLOW64
0043 # define Q_UMULH(v1, v2) __umulh(v1, v2)
0044 # define Q_SMULH(v1, v2) __mulh(v1, v2)
0045 # pragma intrinsic(__umulh)
0046 # pragma intrinsic(__mulh)
0047 # endif
0048 #endif
0049
0050 QT_BEGIN_NAMESPACE
0051
0052
0053 template <typename T>
0054 constexpr typename std::enable_if<std::is_integral<T>::value, bool>::type
0055 qIsInf(T) { return false; }
0056 template <typename T>
0057 constexpr typename std::enable_if<std::is_integral<T>::value, bool>::type
0058 qIsNaN(T) { return false; }
0059 template <typename T>
0060 constexpr typename std::enable_if<std::is_integral<T>::value, bool>::type
0061 qIsFinite(T) { return true; }
0062
0063
0064 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(double d);
0065 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(double d);
0066 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(double d);
0067 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION int qFpClassify(double val);
0068 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(float f);
0069 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(float f);
0070 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(float f);
0071 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION int qFpClassify(float val);
0072
0073 #if QT_CONFIG(signaling_nan)
0074 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qSNaN();
0075 #endif
0076 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qQNaN();
0077 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qInf();
0078
0079 Q_CORE_EXPORT quint32 qFloatDistance(float a, float b);
0080 Q_CORE_EXPORT quint64 qFloatDistance(double a, double b);
0081
0082 #define Q_INFINITY (QT_PREPEND_NAMESPACE(qInf)())
0083 #if QT_CONFIG(signaling_nan)
0084 # define Q_SNAN (QT_PREPEND_NAMESPACE(qSNaN)())
0085 #endif
0086 #define Q_QNAN (QT_PREPEND_NAMESPACE(qQNaN)())
0087
0088
0089
0090
0091
0092
0093
0094
0095 #if defined(Q_CC_GNU_ONLY) \
0096 || defined(Q_CC_CLANG_ONLY) \
0097 || __has_builtin(__builtin_add_overflow)
0098 # define Q_NUMERIC_USE_GCC_OVERFLOW_BUILTINS
0099
0100
0101
0102 # if !(QT_POINTER_SIZE == 4 && defined(Q_CC_CLANG_ONLY) && Q_CC_CLANG_ONLY < 1400)
0103 # define Q_INTRINSIC_MUL_OVERFLOW64
0104 # endif
0105 #endif
0106
0107 namespace QtPrivate {
0108
0109 template <typename T>
0110 constexpr inline
0111 typename std::enable_if_t<std::is_unsigned_v<T>, bool>
0112 qAddOverflowGeneric(T v1, T v2, T *r)
0113 {
0114
0115 *r = v1 + v2;
0116 return v1 > T(v1 + v2);
0117 }
0118
0119
0120
0121
0122
0123 template <typename T>
0124 constexpr inline
0125 typename std::enable_if_t<std::is_same_v<T, decltype(+T{})>, bool>
0126 qMulOverflowWideMultiplication(T v1, T v2, T *r)
0127 {
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160 if (v1 == 0 || v2 == 0) {
0161 *r = T(0);
0162 return false;
0163 }
0164
0165
0166
0167 using U = std::make_unsigned_t<T>;
0168 const U v1_abs = (v1 >= 0) ? U(v1) : (U(0) - U(v1));
0169 const U v2_abs = (v2 >= 0) ? U(v2) : (U(0) - U(v2));
0170
0171
0172 constexpr std::size_t half_width = (sizeof(U) * 8) / 2;
0173 const U half_mask = ~U(0) >> half_width;
0174
0175
0176 const U v1_lo = v1_abs & half_mask;
0177 const U v1_hi = v1_abs >> half_width;
0178 const U v2_lo = v2_abs & half_mask;
0179 const U v2_hi = v2_abs >> half_width;
0180
0181
0182 const U lo_lo = v1_lo * v2_lo;
0183 const U lo_hi = v1_lo * v2_hi;
0184 const U hi_lo = v1_hi * v2_lo;
0185 const U hi_hi = v1_hi * v2_hi;
0186
0187
0188
0189 const U tmp = (lo_lo >> half_width) + (hi_lo & half_mask) + lo_hi;
0190 U result_hi = (hi_lo >> half_width) + (tmp >> half_width) + hi_hi;
0191 U result_lo = (tmp << half_width) | (lo_lo & half_mask);
0192
0193 if constexpr (std::is_unsigned_v<T>) {
0194
0195
0196 *r = result_lo;
0197 return result_hi != U(0);
0198 } else {
0199
0200 const bool isNegative = (v1 < T(0)) != (v2 < T(0));
0201 if (isNegative) {
0202
0203
0204
0205
0206
0207
0208
0209 result_lo = U(0) - result_lo;
0210
0211
0212
0213
0214 result_hi = ~result_hi;
0215 if (result_lo == 0)
0216 result_hi += U(1);
0217 }
0218
0219 *r = result_lo;
0220
0221
0222 return result_hi != U(*r >> std::numeric_limits<T>::digits);
0223 }
0224 }
0225
0226 template <typename T, typename Enable = void>
0227 constexpr inline bool HasLargerInt = false;
0228 template <typename T>
0229 constexpr inline bool HasLargerInt<T, std::void_t<typename QIntegerForSize<sizeof(T) * 2>::Unsigned>> = true;
0230
0231 template <typename T>
0232 constexpr inline
0233 typename std::enable_if_t<(std::is_unsigned_v<T> || std::is_signed_v<T>), bool>
0234 qMulOverflowGeneric(T v1, T v2, T *r)
0235 {
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246 if constexpr (HasLargerInt<T>) {
0247
0248 using LargerInt = QIntegerForSize<sizeof(T) * 2>;
0249 using Larger = typename std::conditional_t<std::is_signed_v<T>,
0250 typename LargerInt::Signed, typename LargerInt::Unsigned>;
0251 Larger lr = Larger(v1) * Larger(v2);
0252 *r = T(lr);
0253 return lr > (std::numeric_limits<T>::max)() || lr < (std::numeric_limits<T>::min)();
0254 } else {
0255
0256 return qMulOverflowWideMultiplication(v1, v2, r);
0257 }
0258 }
0259 }
0260
0261 template <typename T>
0262 constexpr inline
0263 typename std::enable_if_t<std::is_unsigned_v<T>, bool>
0264 qAddOverflow(T v1, T v2, T *r)
0265 {
0266 static_assert(!std::is_same_v<T, char>, "Template must be an integral other than plain 'char'");
0267 #if defined(Q_NUMERIC_USE_GCC_OVERFLOW_BUILTINS)
0268 return __builtin_add_overflow(v1, v2, r);
0269 #else
0270 if (q20::is_constant_evaluated())
0271 return QtPrivate::qAddOverflowGeneric(v1, v2, r);
0272 # if defined(Q_HAVE_ADDCARRY)
0273
0274 if constexpr (std::is_same_v<T, unsigned>) {
0275 return _addcarry_u32(0, v1, v2, r);
0276 } else if constexpr (std::is_same_v<T, quint64>) {
0277 # if defined(Q_PROCESSOR_X86_64)
0278 return _addcarry_u64(0, v1, v2, reinterpret_cast<unsigned __int64 *>(r));
0279 # else
0280 uint low, high;
0281 uchar carry = _addcarry_u32(0, unsigned(v1), unsigned(v2), &low);
0282 carry = _addcarry_u32(carry, v1 >> 32, v2 >> 32, &high);
0283 *r = (quint64(high) << 32) | low;
0284 return carry;
0285 # endif
0286 }
0287 # endif
0288 return QtPrivate::qAddOverflowGeneric(v1, v2, r);
0289 #endif
0290 }
0291
0292 template <typename T>
0293 constexpr inline
0294 typename std::enable_if_t<std::is_signed_v<T>, bool>
0295 qAddOverflow(T v1, T v2, T *r)
0296 {
0297 static_assert(!std::is_same_v<T, char>, "Template must be an integral other than plain 'char'");
0298 #if defined(Q_NUMERIC_USE_GCC_OVERFLOW_BUILTINS)
0299 return __builtin_add_overflow(v1, v2, r);
0300 #else
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310 using U = typename std::make_unsigned_t<T>;
0311 *r = T(U(v1) + U(v2));
0312
0313
0314
0315
0316
0317
0318 return ((v1 ^ *r) & (v2 ^ *r)) < 0;
0319 #endif
0320 }
0321
0322 template <typename T>
0323 constexpr inline
0324 typename std::enable_if_t<std::is_unsigned_v<T>, bool>
0325 qSubOverflow(T v1, T v2, T *r)
0326 {
0327 static_assert(!std::is_same_v<T, char>, "Template must be an integral other than plain 'char'");
0328 #if defined(Q_NUMERIC_USE_GCC_OVERFLOW_BUILTINS)
0329 return __builtin_sub_overflow(v1, v2, r);
0330 #else
0331
0332 *r = v1 - v2;
0333 return v1 < v2;
0334 #endif
0335 }
0336
0337 template <typename T>
0338 constexpr inline
0339 typename std::enable_if_t<std::is_signed_v<T>, bool>
0340 qSubOverflow(T v1, T v2, T *r)
0341 {
0342 static_assert(!std::is_same_v<T, char>, "Template must be an integral other than plain 'char'");
0343 #if defined(Q_NUMERIC_USE_GCC_OVERFLOW_BUILTINS)
0344 return __builtin_sub_overflow(v1, v2, r);
0345 #else
0346
0347
0348
0349
0350 using U = typename std::make_unsigned_t<T>;
0351 *r = T(U(v1) - U(v2));
0352
0353 return ((v1 ^ *r) & (~v2 ^ *r)) < 0;
0354 #endif
0355 }
0356
0357 template <typename T>
0358 constexpr inline
0359 typename std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool>
0360 qMulOverflow(T v1, T v2, T *r)
0361 {
0362 static_assert(!std::is_same_v<T, char>, "Template must be an integral other than plain 'char'");
0363 #if defined(Q_NUMERIC_USE_GCC_OVERFLOW_BUILTINS)
0364 # if defined(Q_INTRINSIC_MUL_OVERFLOW64)
0365 return __builtin_mul_overflow(v1, v2, r);
0366 # else
0367 if constexpr (sizeof(T) <= 4)
0368 return __builtin_mul_overflow(v1, v2, r);
0369 else
0370 return QtPrivate::qMulOverflowGeneric(v1, v2, r);
0371 # endif
0372 #else
0373 if (q20::is_constant_evaluated())
0374 return QtPrivate::qMulOverflowGeneric(v1, v2, r);
0375
0376 # if defined(Q_INTRINSIC_MUL_OVERFLOW64)
0377 if constexpr (std::is_unsigned_v<T> && (sizeof(T) == sizeof(quint64))) {
0378
0379
0380 *r = v1 * v2;
0381 return T(Q_UMULH(v1, v2));
0382 } else if constexpr (std::is_signed_v<T> && (sizeof(T) == sizeof(qint64))) {
0383
0384
0385
0386
0387
0388
0389 qint64 high = Q_SMULH(v1, v2);
0390 *r = qint64(quint64(v1) * quint64(v2));
0391 return (*r >> 63) != high;
0392 }
0393 # endif
0394
0395 return QtPrivate::qMulOverflowGeneric(v1, v2, r);
0396 #endif
0397 }
0398
0399 #undef Q_HAVE_ADDCARRY
0400 #undef Q_NUMERIC_USE_GCC_OVERFLOW_BUILTINS
0401
0402
0403
0404
0405
0406
0407 template <typename T, T V2> constexpr bool qAddOverflow(T v1, std::integral_constant<T, V2>, T *r)
0408 {
0409 return qAddOverflow(v1, V2, r);
0410 }
0411
0412 template <auto V2, typename T> constexpr bool qAddOverflow(T v1, T *r)
0413 {
0414 return qAddOverflow(v1, std::integral_constant<T, V2>{}, r);
0415 }
0416
0417 template <typename T, T V2> constexpr bool qSubOverflow(T v1, std::integral_constant<T, V2>, T *r)
0418 {
0419 return qSubOverflow(v1, V2, r);
0420 }
0421
0422 template <auto V2, typename T> constexpr bool qSubOverflow(T v1, T *r)
0423 {
0424 return qSubOverflow(v1, std::integral_constant<T, V2>{}, r);
0425 }
0426
0427 template <typename T, T V2> constexpr bool qMulOverflow(T v1, std::integral_constant<T, V2>, T *r)
0428 {
0429 static_assert(!std::is_same_v<T, char>, "Template must be an integral other than plain 'char'");
0430
0431
0432
0433
0434
0435 if constexpr (sizeof(T) <= sizeof(qregisteruint)) {
0436 return qMulOverflow(v1, V2, r);
0437
0438 #ifdef Q_INTRINSIC_MUL_OVERFLOW64
0439 } else if constexpr (sizeof(T) <= sizeof(quint64)) {
0440
0441
0442 return qMulOverflow(v1, V2, r);
0443 #endif
0444
0445 } else if constexpr (V2 == 0 || V2 == 1) {
0446
0447 *r = v1 * V2;
0448 return false;
0449 } else if constexpr (V2 == -1) {
0450
0451
0452 if (v1 < 0 && v1 == (std::numeric_limits<T>::min)())
0453 return true;
0454 *r = -v1;
0455 return false;
0456 } else {
0457
0458
0459 constexpr T Highest = (std::numeric_limits<T>::max)() / V2;
0460 constexpr T Lowest = (std::numeric_limits<T>::min)() / V2;
0461 if constexpr (Highest > Lowest) {
0462 if (v1 > Highest || v1 < Lowest)
0463 return true;
0464 } else {
0465
0466 static_assert(V2 < 0);
0467 if (v1 > Lowest || v1 < Highest)
0468 return true;
0469 }
0470
0471 *r = v1 * V2;
0472 return false;
0473 }
0474 }
0475
0476 template <auto V2, typename T> constexpr bool qMulOverflow(T v1, T *r)
0477 {
0478 if constexpr (V2 == 2)
0479 return qAddOverflow(v1, v1, r);
0480 return qMulOverflow(v1, std::integral_constant<T, V2>{}, r);
0481 }
0482
0483 template <typename T>
0484 constexpr inline T qAbs(const T &t)
0485 {
0486 if constexpr (std::is_integral_v<T> && std::is_signed_v<T>)
0487 Q_ASSERT(t != std::numeric_limits<T>::min());
0488 return t >= 0 ? t : -t;
0489 }
0490
0491 namespace QtPrivate {
0492 template <typename T,
0493 typename std::enable_if_t<std::is_integral_v<T>, bool> = true>
0494 constexpr inline auto qUnsignedAbs(T t)
0495 {
0496 using U = std::make_unsigned_t<T>;
0497 return (t >= 0) ? U(t) : U(~U(t) + U(1));
0498 }
0499
0500 template <typename Result,
0501 typename FP,
0502 typename std::enable_if_t<std::is_integral_v<Result>, bool> = true,
0503 typename std::enable_if_t<std::is_floating_point_v<FP>, bool> = true>
0504 constexpr inline Result qCheckedFPConversionToInteger(FP value)
0505 {
0506 #ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
0507 if (!q20::is_constant_evaluated())
0508 Q_ASSERT(!std::isnan(value));
0509 #endif
0510
0511 constexpr Result minimal = (std::numeric_limits<Result>::min)();
0512 constexpr Result maximal = (std::numeric_limits<Result>::max)();
0513
0514
0515
0516
0517 Q_ASSERT(value - FP(minimal) > FP(-1));
0518
0519
0520
0521 constexpr FP maximalPlusOne = FP(2) * (maximal / 2 + 1);
0522
0523 Q_ASSERT(value < maximalPlusOne);
0524
0525
0526
0527 return Result(value);
0528 }
0529
0530 namespace QRoundImpl {
0531
0532 #if defined(Q_PROCESSOR_ARM_64) && (__has_builtin(__builtin_round) || defined(Q_CC_GNU)) && !defined(Q_CC_CLANG)
0533
0534
0535 constexpr inline double qRound(double d)
0536 { return __builtin_round(d); }
0537 constexpr inline float qRound(float f)
0538 { return __builtin_roundf(f); }
0539 #elif defined(__SSE2__) && (__has_builtin(__builtin_copysign) || defined(Q_CC_GNU))
0540
0541 constexpr inline double qRound(double d)
0542 { return d + __builtin_copysign(0.5, d); }
0543 constexpr inline float qRound(float f)
0544 { return f + __builtin_copysignf(0.5f, f); }
0545 #else
0546 constexpr inline double qRound(double d)
0547 { return d >= 0.0 ? d + 0.5 : d - 0.5; }
0548 constexpr inline float qRound(float d)
0549 { return d >= 0.0f ? d + 0.5f : d - 0.5f; }
0550 #endif
0551 }
0552
0553
0554
0555 template <typename FP,
0556 typename std::enable_if_t<std::is_floating_point_v<FP>, bool> = true>
0557 constexpr inline int qSaturateRound(FP value)
0558 {
0559 #ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
0560 if (!q20::is_constant_evaluated())
0561 Q_ASSERT(!qIsNaN(value));
0562 #endif
0563 constexpr FP MinBound = FP((std::numeric_limits<int>::min)());
0564 constexpr FP MaxBound = FP((std::numeric_limits<int>::max)());
0565 const FP beforeTruncation = QRoundImpl::qRound(value);
0566 return int(qBound(MinBound, beforeTruncation, MaxBound));
0567 }
0568 }
0569
0570 constexpr inline int qRound(double d)
0571 {
0572 return QtPrivate::qCheckedFPConversionToInteger<int>(QtPrivate::QRoundImpl::qRound(d));
0573 }
0574
0575 constexpr inline int qRound(float f)
0576 {
0577 return QtPrivate::qCheckedFPConversionToInteger<int>(QtPrivate::QRoundImpl::qRound(f));
0578 }
0579
0580 constexpr inline qint64 qRound64(double d)
0581 {
0582 return QtPrivate::qCheckedFPConversionToInteger<qint64>(QtPrivate::QRoundImpl::qRound(d));
0583 }
0584
0585 constexpr inline qint64 qRound64(float f)
0586 {
0587 return QtPrivate::qCheckedFPConversionToInteger<qint64>(QtPrivate::QRoundImpl::qRound(f));
0588 }
0589
0590 namespace QtPrivate {
0591 template <typename T>
0592 constexpr inline const T &min(const T &a, const T &b) { return (a < b) ? a : b; }
0593 }
0594
0595 [[nodiscard]] constexpr bool qFuzzyCompare(double p1, double p2) noexcept
0596 {
0597 return (qAbs(p1 - p2) * 1000000000000. <= QtPrivate::min(qAbs(p1), qAbs(p2)));
0598 }
0599
0600 [[nodiscard]] constexpr bool qFuzzyCompare(float p1, float p2) noexcept
0601 {
0602 return (qAbs(p1 - p2) * 100000.f <= QtPrivate::min(qAbs(p1), qAbs(p2)));
0603 }
0604
0605 [[nodiscard]] constexpr bool qFuzzyIsNull(double d) noexcept
0606 {
0607 return qAbs(d) <= 0.000000000001;
0608 }
0609
0610 [[nodiscard]] constexpr bool qFuzzyIsNull(float f) noexcept
0611 {
0612 return qAbs(f) <= 0.00001f;
0613 }
0614
0615 QT_WARNING_PUSH
0616 QT_WARNING_DISABLE_FLOAT_COMPARE
0617
0618 [[nodiscard]] constexpr bool qIsNull(double d) noexcept
0619 {
0620 return d == 0.0;
0621 }
0622
0623 [[nodiscard]] constexpr bool qIsNull(float f) noexcept
0624 {
0625 return f == 0.0f;
0626 }
0627
0628 QT_WARNING_POP
0629
0630 namespace QtPrivate {
0631
0632
0633
0634
0635
0636
0637
0638
0639
0640 template <typename T, typename S>
0641 [[nodiscard]] constexpr bool fuzzyCompare(const T &lhs, const S &rhs) noexcept
0642 {
0643 static_assert(noexcept(qIsNull(lhs) && qIsNull(rhs) && qFuzzyIsNull(lhs - rhs) && qFuzzyCompare(lhs, rhs)),
0644 "The operations qIsNull(), qFuzzyIsNull() and qFuzzyCompare() must be noexcept "
0645 "for both argument types!");
0646 return qIsNull(lhs) || qIsNull(rhs) ? qFuzzyIsNull(lhs - rhs) : qFuzzyCompare(lhs, rhs);
0647 }
0648 }
0649
0650
0651 inline int qIntCast(double f) { return int(f); }
0652 inline int qIntCast(float f) { return int(f); }
0653
0654 QT_END_NAMESPACE
0655
0656 #endif