File indexing completed on 2026-05-07 08:48:16
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 #if defined(Q_NUMERIC_USE_GCC_OVERFLOW_BUILTINS)
0267 return __builtin_add_overflow(v1, v2, r);
0268 #else
0269 if (q20::is_constant_evaluated())
0270 return QtPrivate::qAddOverflowGeneric(v1, v2, r);
0271 # if defined(Q_HAVE_ADDCARRY)
0272
0273 if constexpr (std::is_same_v<T, unsigned>) {
0274 return _addcarry_u32(0, v1, v2, r);
0275 } else if constexpr (std::is_same_v<T, quint64>) {
0276 # if defined(Q_PROCESSOR_X86_64)
0277 return _addcarry_u64(0, v1, v2, reinterpret_cast<unsigned __int64 *>(r));
0278 # else
0279 uint low, high;
0280 uchar carry = _addcarry_u32(0, unsigned(v1), unsigned(v2), &low);
0281 carry = _addcarry_u32(carry, v1 >> 32, v2 >> 32, &high);
0282 *r = (quint64(high) << 32) | low;
0283 return carry;
0284 # endif
0285 }
0286 # endif
0287 return QtPrivate::qAddOverflowGeneric(v1, v2, r);
0288 #endif
0289 }
0290
0291 template <typename T>
0292 constexpr inline
0293 typename std::enable_if_t<std::is_signed_v<T>, bool>
0294 qAddOverflow(T v1, T v2, T *r)
0295 {
0296 #if defined(Q_NUMERIC_USE_GCC_OVERFLOW_BUILTINS)
0297 return __builtin_add_overflow(v1, v2, r);
0298 #else
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308 using U = typename std::make_unsigned_t<T>;
0309 *r = T(U(v1) + U(v2));
0310
0311
0312
0313
0314
0315
0316 return ((v1 ^ *r) & (v2 ^ *r)) < 0;
0317 #endif
0318 }
0319
0320 template <typename T>
0321 constexpr inline
0322 typename std::enable_if_t<std::is_unsigned_v<T>, bool>
0323 qSubOverflow(T v1, T v2, T *r)
0324 {
0325 #if defined(Q_NUMERIC_USE_GCC_OVERFLOW_BUILTINS)
0326 return __builtin_sub_overflow(v1, v2, r);
0327 #else
0328
0329 *r = v1 - v2;
0330 return v1 < v2;
0331 #endif
0332 }
0333
0334 template <typename T>
0335 constexpr inline
0336 typename std::enable_if_t<std::is_signed_v<T>, bool>
0337 qSubOverflow(T v1, T v2, T *r)
0338 {
0339 #if defined(Q_NUMERIC_USE_GCC_OVERFLOW_BUILTINS)
0340 return __builtin_sub_overflow(v1, v2, r);
0341 #else
0342
0343
0344
0345
0346 using U = typename std::make_unsigned_t<T>;
0347 *r = T(U(v1) - U(v2));
0348
0349 return ((v1 ^ *r) & (~v2 ^ *r)) < 0;
0350 #endif
0351 }
0352
0353 template <typename T>
0354 constexpr inline
0355 typename std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool>
0356 qMulOverflow(T v1, T v2, T *r)
0357 {
0358 #if defined(Q_NUMERIC_USE_GCC_OVERFLOW_BUILTINS)
0359 # if defined(Q_INTRINSIC_MUL_OVERFLOW64)
0360 return __builtin_mul_overflow(v1, v2, r);
0361 # else
0362 if constexpr (sizeof(T) <= 4)
0363 return __builtin_mul_overflow(v1, v2, r);
0364 else
0365 return QtPrivate::qMulOverflowGeneric(v1, v2, r);
0366 # endif
0367 #else
0368 if (q20::is_constant_evaluated())
0369 return QtPrivate::qMulOverflowGeneric(v1, v2, r);
0370
0371 # if defined(Q_INTRINSIC_MUL_OVERFLOW64)
0372 if constexpr (std::is_unsigned_v<T> && (sizeof(T) == sizeof(quint64))) {
0373
0374
0375 *r = v1 * v2;
0376 return T(Q_UMULH(v1, v2));
0377 } else if constexpr (std::is_signed_v<T> && (sizeof(T) == sizeof(qint64))) {
0378
0379
0380
0381
0382
0383
0384 qint64 high = Q_SMULH(v1, v2);
0385 *r = qint64(quint64(v1) * quint64(v2));
0386 return (*r >> 63) != high;
0387 }
0388 # endif
0389
0390 return QtPrivate::qMulOverflowGeneric(v1, v2, r);
0391 #endif
0392 }
0393
0394 #undef Q_HAVE_ADDCARRY
0395 #undef Q_NUMERIC_USE_GCC_OVERFLOW_BUILTINS
0396
0397
0398
0399
0400
0401
0402 template <typename T, T V2> constexpr bool qAddOverflow(T v1, std::integral_constant<T, V2>, T *r)
0403 {
0404 return qAddOverflow(v1, V2, r);
0405 }
0406
0407 template <auto V2, typename T> constexpr bool qAddOverflow(T v1, T *r)
0408 {
0409 return qAddOverflow(v1, std::integral_constant<T, V2>{}, r);
0410 }
0411
0412 template <typename T, T V2> constexpr bool qSubOverflow(T v1, std::integral_constant<T, V2>, T *r)
0413 {
0414 return qSubOverflow(v1, V2, r);
0415 }
0416
0417 template <auto V2, typename T> constexpr bool qSubOverflow(T v1, T *r)
0418 {
0419 return qSubOverflow(v1, std::integral_constant<T, V2>{}, r);
0420 }
0421
0422 template <typename T, T V2> constexpr bool qMulOverflow(T v1, std::integral_constant<T, V2>, T *r)
0423 {
0424
0425
0426
0427
0428 if constexpr (sizeof(T) <= sizeof(qregisteruint)) {
0429 return qMulOverflow(v1, V2, r);
0430
0431 #ifdef Q_INTRINSIC_MUL_OVERFLOW64
0432 } else if constexpr (sizeof(T) <= sizeof(quint64)) {
0433
0434
0435 return qMulOverflow(v1, V2, r);
0436 #endif
0437
0438 } else if constexpr (V2 == 0 || V2 == 1) {
0439
0440 *r = v1 * V2;
0441 return false;
0442 } else if constexpr (V2 == -1) {
0443
0444
0445 if (v1 < 0 && v1 == (std::numeric_limits<T>::min)())
0446 return true;
0447 *r = -v1;
0448 return false;
0449 } else {
0450
0451
0452 constexpr T Highest = (std::numeric_limits<T>::max)() / V2;
0453 constexpr T Lowest = (std::numeric_limits<T>::min)() / V2;
0454 if constexpr (Highest > Lowest) {
0455 if (v1 > Highest || v1 < Lowest)
0456 return true;
0457 } else {
0458
0459 static_assert(V2 < 0);
0460 if (v1 > Lowest || v1 < Highest)
0461 return true;
0462 }
0463
0464 *r = v1 * V2;
0465 return false;
0466 }
0467 }
0468
0469 template <auto V2, typename T> constexpr bool qMulOverflow(T v1, T *r)
0470 {
0471 if constexpr (V2 == 2)
0472 return qAddOverflow(v1, v1, r);
0473 return qMulOverflow(v1, std::integral_constant<T, V2>{}, r);
0474 }
0475
0476 template <typename T>
0477 constexpr inline T qAbs(const T &t)
0478 {
0479 if constexpr (std::is_integral_v<T> && std::is_signed_v<T>)
0480 Q_ASSERT(t != std::numeric_limits<T>::min());
0481 return t >= 0 ? t : -t;
0482 }
0483
0484 namespace QtPrivate {
0485 template <typename T,
0486 typename std::enable_if_t<std::is_integral_v<T>, bool> = true>
0487 constexpr inline auto qUnsignedAbs(T t)
0488 {
0489 using U = std::make_unsigned_t<T>;
0490 return (t >= 0) ? U(t) : U(~U(t) + U(1));
0491 }
0492
0493 template <typename Result,
0494 typename FP,
0495 typename std::enable_if_t<std::is_integral_v<Result>, bool> = true,
0496 typename std::enable_if_t<std::is_floating_point_v<FP>, bool> = true>
0497 constexpr inline Result qCheckedFPConversionToInteger(FP value)
0498 {
0499 #ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
0500 if (!q20::is_constant_evaluated())
0501 Q_ASSERT(!std::isnan(value));
0502 #endif
0503
0504 constexpr Result minimal = (std::numeric_limits<Result>::min)();
0505 constexpr Result maximal = (std::numeric_limits<Result>::max)();
0506
0507
0508
0509
0510 Q_ASSERT(value - FP(minimal) > FP(-1));
0511
0512
0513
0514 constexpr FP maximalPlusOne = FP(2) * (maximal / 2 + 1);
0515
0516 Q_ASSERT(value < maximalPlusOne);
0517
0518
0519
0520 return Result(value);
0521 }
0522
0523 namespace QRoundImpl {
0524
0525 #if defined(Q_PROCESSOR_ARM_64) && (__has_builtin(__builtin_round) || defined(Q_CC_GNU)) && !defined(Q_CC_CLANG)
0526
0527
0528 constexpr inline double qRound(double d)
0529 { return __builtin_round(d); }
0530 constexpr inline float qRound(float f)
0531 { return __builtin_roundf(f); }
0532 #elif defined(__SSE2__) && (__has_builtin(__builtin_copysign) || defined(Q_CC_GNU))
0533
0534 constexpr inline double qRound(double d)
0535 { return d + __builtin_copysign(0.5, d); }
0536 constexpr inline float qRound(float f)
0537 { return f + __builtin_copysignf(0.5f, f); }
0538 #else
0539 constexpr inline double qRound(double d)
0540 { return d >= 0.0 ? d + 0.5 : d - 0.5; }
0541 constexpr inline float qRound(float d)
0542 { return d >= 0.0f ? d + 0.5f : d - 0.5f; }
0543 #endif
0544 }
0545
0546
0547
0548 template <typename FP,
0549 typename std::enable_if_t<std::is_floating_point_v<FP>, bool> = true>
0550 constexpr inline int qSaturateRound(FP value)
0551 {
0552 #ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
0553 if (!q20::is_constant_evaluated())
0554 Q_ASSERT(!qIsNaN(value));
0555 #endif
0556 constexpr FP MinBound = FP((std::numeric_limits<int>::min)());
0557 constexpr FP MaxBound = FP((std::numeric_limits<int>::max)());
0558 const FP beforeTruncation = QRoundImpl::qRound(value);
0559 return int(qBound(MinBound, beforeTruncation, MaxBound));
0560 }
0561 }
0562
0563 constexpr inline int qRound(double d)
0564 {
0565 return QtPrivate::qCheckedFPConversionToInteger<int>(QtPrivate::QRoundImpl::qRound(d));
0566 }
0567
0568 constexpr inline int qRound(float f)
0569 {
0570 return QtPrivate::qCheckedFPConversionToInteger<int>(QtPrivate::QRoundImpl::qRound(f));
0571 }
0572
0573 constexpr inline qint64 qRound64(double d)
0574 {
0575 return QtPrivate::qCheckedFPConversionToInteger<qint64>(QtPrivate::QRoundImpl::qRound(d));
0576 }
0577
0578 constexpr inline qint64 qRound64(float f)
0579 {
0580 return QtPrivate::qCheckedFPConversionToInteger<qint64>(QtPrivate::QRoundImpl::qRound(f));
0581 }
0582
0583 namespace QtPrivate {
0584 template <typename T>
0585 constexpr inline const T &min(const T &a, const T &b) { return (a < b) ? a : b; }
0586 }
0587
0588 [[nodiscard]] constexpr bool qFuzzyCompare(double p1, double p2) noexcept
0589 {
0590 return (qAbs(p1 - p2) * 1000000000000. <= QtPrivate::min(qAbs(p1), qAbs(p2)));
0591 }
0592
0593 [[nodiscard]] constexpr bool qFuzzyCompare(float p1, float p2) noexcept
0594 {
0595 return (qAbs(p1 - p2) * 100000.f <= QtPrivate::min(qAbs(p1), qAbs(p2)));
0596 }
0597
0598 [[nodiscard]] constexpr bool qFuzzyIsNull(double d) noexcept
0599 {
0600 return qAbs(d) <= 0.000000000001;
0601 }
0602
0603 [[nodiscard]] constexpr bool qFuzzyIsNull(float f) noexcept
0604 {
0605 return qAbs(f) <= 0.00001f;
0606 }
0607
0608 QT_WARNING_PUSH
0609 QT_WARNING_DISABLE_FLOAT_COMPARE
0610
0611 [[nodiscard]] constexpr bool qIsNull(double d) noexcept
0612 {
0613 return d == 0.0;
0614 }
0615
0616 [[nodiscard]] constexpr bool qIsNull(float f) noexcept
0617 {
0618 return f == 0.0f;
0619 }
0620
0621 QT_WARNING_POP
0622
0623 namespace QtPrivate {
0624
0625
0626
0627
0628
0629
0630
0631
0632
0633 template <typename T, typename S>
0634 [[nodiscard]] constexpr bool fuzzyCompare(const T &lhs, const S &rhs) noexcept
0635 {
0636 static_assert(noexcept(qIsNull(lhs) && qIsNull(rhs) && qFuzzyIsNull(lhs - rhs) && qFuzzyCompare(lhs, rhs)),
0637 "The operations qIsNull(), qFuzzyIsNull() and qFuzzyCompare() must be noexcept "
0638 "for both argument types!");
0639 return qIsNull(lhs) || qIsNull(rhs) ? qFuzzyIsNull(lhs - rhs) : qFuzzyCompare(lhs, rhs);
0640 }
0641 }
0642
0643
0644 inline int qIntCast(double f) { return int(f); }
0645 inline int qIntCast(float f) { return int(f); }
0646
0647 QT_END_NAMESPACE
0648
0649 #endif