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