summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp')
-rw-r--r--tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp483
1 files changed, 269 insertions, 214 deletions
diff --git a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
index da52e6e026..d21fabd74e 100644
--- a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
+++ b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
@@ -1,34 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#include <QtTest/QtTest>
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+
+#include <QTest>
#include <QtGlobal>
#include "private/qnumeric_p.h"
@@ -52,6 +27,8 @@ class tst_QNumeric: public QObject
// Support for floating-point:
template<typename F> inline void fuzzyCompare_data();
template<typename F> inline void fuzzyCompare();
+ template<typename F> inline void fuzzyIsNull_data();
+ template<typename F> inline void fuzzyIsNull();
template<typename F> inline void checkNaN(F nan);
template<typename F> inline void rawNaN_data();
template<typename F> inline void rawNaN();
@@ -71,6 +48,10 @@ private slots:
void fuzzyCompareF() { fuzzyCompare<float>(); }
void fuzzyCompareD_data() { fuzzyCompare_data<double>(); }
void fuzzyCompareD() { fuzzyCompare<double>(); }
+ void fuzzyIsNullF_data() { fuzzyIsNull_data<float>(); }
+ void fuzzyIsNullF() { fuzzyIsNull<float>(); }
+ void fuzzyIsNullD_data() { fuzzyIsNull_data<double>(); }
+ void fuzzyIsNullD() { fuzzyIsNull<double>(); }
void rawNaNF_data() { rawNaN_data<float>(); }
void rawNaNF() { rawNaN<float>(); }
void rawNaND_data() { rawNaN_data<double>(); }
@@ -110,7 +91,7 @@ void tst_QNumeric::fuzzyCompare_data()
QTest::addColumn<bool>("isEqual");
const F zero(0), one(1), ten(10);
const F huge = Fuzzy<F>::scale, tiny = one / huge;
- const F deci(.1), giga(1e9), nano(1e-9), big(1e7), small(1e-10);
+ const F deci(.1f), giga(1e9f), nano(1e-9f), big(1e7f), small(1e-10f);
QTest::newRow("zero") << zero << zero << true;
QTest::newRow("ten") << ten << ten << true;
@@ -143,6 +124,45 @@ void tst_QNumeric::fuzzyCompare()
QCOMPARE(::qFuzzyCompare(-val2, -val1), isEqual);
}
+template<typename F>
+void tst_QNumeric::fuzzyIsNull_data()
+{
+ QTest::addColumn<F>("value");
+ QTest::addColumn<bool>("isNull");
+ using Bounds = std::numeric_limits<F>;
+ const F one(1), huge = Fuzzy<F>::scale, tiny = one / huge;
+
+ QTest::newRow("zero") << F(0) << true;
+ QTest::newRow("min") << Bounds::min() << true;
+ QTest::newRow("denorm_min") << Bounds::denorm_min() << true;
+ QTest::newRow("tiny") << tiny << true;
+
+ QTest::newRow("deci") << F(.1) << false;
+ QTest::newRow("one") << one << false;
+ QTest::newRow("ten") << F(10) << false;
+ QTest::newRow("large") << F(1e9) << false;
+ QTest::newRow("huge") << huge << false;
+}
+
+template<typename F>
+void tst_QNumeric::fuzzyIsNull()
+{
+ QFETCH(F, value);
+ QFETCH(bool, isNull);
+
+ QCOMPARE(::qFuzzyIsNull(value), isNull);
+ QCOMPARE(::qFuzzyIsNull(-value), isNull);
+}
+
+static void clearFpExceptions()
+{
+ // Call after any functions that exercise floating-point exceptions, such as
+ // sqrt(-1) or log(0).
+#ifdef Q_OS_WIN
+ _clearfp();
+#endif
+}
+
#if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)
// turn -ffast-math off
# pragma GCC optimize "no-fast-math"
@@ -151,6 +171,7 @@ void tst_QNumeric::fuzzyCompare()
template<typename F>
void tst_QNumeric::checkNaN(F nan)
{
+ const auto cleanup = qScopeGuard([]() { clearFpExceptions(); });
#define CHECKNAN(value) \
do { \
const F v = (value); \
@@ -159,21 +180,23 @@ void tst_QNumeric::checkNaN(F nan)
QVERIFY(!qIsFinite(v)); \
QVERIFY(!qIsInf(v)); \
} while (0)
+ const F zero(0), one(1), two(2);
- QVERIFY(!(0 > nan));
- QVERIFY(!(0 < nan));
- QVERIFY(!(0 == nan));
+ QVERIFY(!(zero > nan));
+ QVERIFY(!(zero < nan));
+ QVERIFY(!(zero == nan));
QVERIFY(!(nan == nan));
CHECKNAN(nan);
- CHECKNAN(nan + 1);
- CHECKNAN(nan - 1);
+ CHECKNAN(nan + one);
+ CHECKNAN(nan - one);
CHECKNAN(-nan);
- CHECKNAN(nan * 2.0);
- CHECKNAN(nan / 2.0);
- CHECKNAN(1.0 / nan);
- CHECKNAN(0.0 / nan);
- CHECKNAN(0.0 * nan);
+ CHECKNAN(nan * two);
+ CHECKNAN(nan / two);
+ CHECKNAN(one / nan);
+ CHECKNAN(zero / nan);
+ CHECKNAN(zero * nan);
+ CHECKNAN(sqrt(-one));
// When any NaN is expected, any NaN will do:
QCOMPARE(nan, nan);
@@ -261,6 +284,7 @@ void tst_QNumeric::generalNaN()
template<typename F>
void tst_QNumeric::infinity()
{
+ const auto cleanup = qScopeGuard([]() { clearFpExceptions(); });
const F inf = qInf();
const F zero(0), one(1), two(2);
QVERIFY(inf > zero);
@@ -283,6 +307,7 @@ void tst_QNumeric::infinity()
QCOMPARE(one / -inf, zero);
QVERIFY(qIsNaN(zero * inf));
QVERIFY(qIsNaN(zero * -inf));
+ QCOMPARE(log(zero), -inf);
}
template<typename F>
@@ -296,8 +321,11 @@ void tst_QNumeric::classifyfp()
QCOMPARE(qFpClassify(inf), FP_INFINITE);
QCOMPARE(qFpClassify(-inf), FP_INFINITE);
+ QT_WARNING_PUSH;
+ QT_WARNING_DISABLE_MSVC(4056);
QCOMPARE(qFpClassify(huge * two), FP_INFINITE);
QCOMPARE(qFpClassify(huge * -two), FP_INFINITE);
+ QT_WARNING_POP;
QCOMPARE(qFpClassify(one), FP_NORMAL);
QCOMPARE(qFpClassify(huge), FP_NORMAL);
@@ -366,10 +394,13 @@ void tst_QNumeric::distance()
QFETCH(F, from);
QFETCH(F, stop);
QFETCH(Count, expectedDistance);
-#ifdef Q_OS_QNX
- QEXPECT_FAIL("denormal", "See QTBUG-37094", Continue);
-#endif
+ if constexpr (std::numeric_limits<F>::has_denorm != std::denorm_present) {
+ if (qstrcmp(QTest::currentDataTag(), "denormal") == 0) {
+ QSKIP("Skipping 'denorm' as this type lacks denormals on this system");
+ }
+ }
QCOMPARE(qFloatDistance(from, stop), expectedDistance);
+ QCOMPARE(qFloatDistance(stop, from), expectedDistance);
}
// Whole number tests:
@@ -400,119 +431,138 @@ template <typename Int> static void addOverflow_template()
#if defined(Q_CC_MSVC) && Q_CC_MSVC < 2000
QSKIP("Test disabled, this test generates an Internal Compiler Error compiling in release mode");
#else
- const Int max = std::numeric_limits<Int>::max();
- const Int min = std::numeric_limits<Int>::min();
+ constexpr Int max = std::numeric_limits<Int>::max();
+ constexpr Int min = std::numeric_limits<Int>::min();
Int r;
+#define ADD_COMPARE_NONOVF(v1, v2, expected) \
+ do { \
+ QCOMPARE(qAddOverflow(Int(v1), Int(v2), &r), false); \
+ QCOMPARE(r, Int(expected)); \
+ QCOMPARE(qAddOverflow(Int(v1), (std::integral_constant<Int, Int(v2)>()), &r), false); \
+ QCOMPARE(r, Int(expected)); \
+ QCOMPARE(qAddOverflow<v2>(Int(v1), &r), false); \
+ QCOMPARE(r, Int(expected)); \
+ } while (false)
+#define ADD_COMPARE_OVF(v1, v2) \
+ do { \
+ QCOMPARE(qAddOverflow(Int(v1), Int(v2), &r), true); \
+ QCOMPARE(qAddOverflow(Int(v1), (std::integral_constant<Int, Int(v2)>()), &r), true); \
+ QCOMPARE(qAddOverflow<v2>(Int(v1), &r), true); \
+ } while (false)
+#define SUB_COMPARE_NONOVF(v1, v2, expected) \
+ do { \
+ QCOMPARE(qSubOverflow(Int(v1), Int(v2), &r), false); \
+ QCOMPARE(r, Int(expected)); \
+ QCOMPARE(qSubOverflow(Int(v1), (std::integral_constant<Int, Int(v2)>()), &r), false); \
+ QCOMPARE(r, Int(expected)); \
+ QCOMPARE(qSubOverflow<v2>(Int(v1), &r), false); \
+ QCOMPARE(r, Int(expected)); \
+ } while (false)
+#define SUB_COMPARE_OVF(v1, v2) \
+ do { \
+ QCOMPARE(qSubOverflow(Int(v1), Int(v2), &r), true); \
+ QCOMPARE(qSubOverflow(Int(v1), (std::integral_constant<Int, Int(v2)>()), &r), true); \
+ QCOMPARE(qSubOverflow<v2>(Int(v1), &r), true); \
+ } while (false)
+
// basic values
- QCOMPARE(add_overflow(Int(0), Int(0), &r), false);
- QCOMPARE(r, Int(0));
- QCOMPARE(add_overflow(Int(1), Int(0), &r), false);
- QCOMPARE(r, Int(1));
- QCOMPARE(add_overflow(Int(0), Int(1), &r), false);
- QCOMPARE(r, Int(1));
-
- QCOMPARE(sub_overflow(Int(0), Int(0), &r), false);
- QCOMPARE(r, Int(0));
- QCOMPARE(sub_overflow(Int(1), Int(0), &r), false);
- QCOMPARE(r, Int(1));
- QCOMPARE(sub_overflow(Int(1), Int(1), &r), false);
- QCOMPARE(r, Int(0));
- QCOMPARE(sub_overflow(Int(0), Int(1), &r), !min);
+ ADD_COMPARE_NONOVF(0, 0, 0);
+ ADD_COMPARE_NONOVF(1, 0, 1);
+ ADD_COMPARE_NONOVF(0, 1, 1);
+
+ SUB_COMPARE_NONOVF(0, 0, 0);
+ SUB_COMPARE_NONOVF(1, 0, 1);
+ SUB_COMPARE_NONOVF(1, 1, 0);
if (min)
- QCOMPARE(r, Int(-1));
+ SUB_COMPARE_NONOVF(0, 1, -1);
+ else
+ SUB_COMPARE_OVF(0, 1);
// half-way through max
- QCOMPARE(add_overflow(Int(max/2), Int(max/2), &r), false);
- QCOMPARE(r, Int(max / 2 * 2));
- QCOMPARE(sub_overflow(Int(max/2), Int(max/2), &r), false);
- QCOMPARE(r, Int(0));
- QCOMPARE(add_overflow(Int(max/2 - 1), Int(max/2 + 1), &r), false);
- QCOMPARE(r, Int(max / 2 * 2));
- QCOMPARE(sub_overflow(Int(max/2 - 1), Int(max/2 + 1), &r), !min);
+ ADD_COMPARE_NONOVF(max/2, max/2, max / 2 * 2);
+ SUB_COMPARE_NONOVF(max/2, max/2, 0);
+ ADD_COMPARE_NONOVF(max/2 - 1, max/2 + 1, max / 2 * 2);
if (min)
- QCOMPARE(r, Int(-2));
- QCOMPARE(add_overflow(Int(max/2 + 1), Int(max/2), &r), false);
- QCOMPARE(r, max);
- QCOMPARE(sub_overflow(Int(max/2 + 1), Int(max/2), &r), false);
- QCOMPARE(r, Int(1));
- QCOMPARE(add_overflow(Int(max/2), Int(max/2 + 1), &r), false);
- QCOMPARE(r, max);
- QCOMPARE(sub_overflow(Int(max/2), Int(max/2 + 1), &r), !min);
+ SUB_COMPARE_NONOVF(max/2 - 1, max/2 + 1, -2);
+ else
+ SUB_COMPARE_OVF(max/2 - 1, max/2 + 1);
+
+ ADD_COMPARE_NONOVF(max/2 + 1, max/2, max);
+ SUB_COMPARE_NONOVF(max/2 + 1, max/2, 1);
+ ADD_COMPARE_NONOVF(max/2, max/2 + 1, max);
if (min)
- QCOMPARE(r, Int(-1));
+ SUB_COMPARE_NONOVF(max/2, max/2 + 1, -1);
+ else
+ SUB_COMPARE_OVF(max/2, max/2 + 1);
- QCOMPARE(add_overflow(Int(min/2), Int(min/2), &r), false);
- QCOMPARE(r, Int(min / 2 * 2));
- QCOMPARE(sub_overflow(Int(min/2), Int(min/2), &r), false);
- QCOMPARE(r, Int(0));
- QCOMPARE(add_overflow(Int(min/2 - 1), Int(min/2 + 1), &r), !min);
+ ADD_COMPARE_NONOVF(min/2, min/2, min / 2 * 2);
+ SUB_COMPARE_NONOVF(min/2, min/2, 0);
if (min)
- QCOMPARE(r, Int(min / 2 * 2));
- QCOMPARE(sub_overflow(Int(min/2 - 1), Int(min/2 + 1), &r), false);
- QCOMPARE(r, Int(-2));
- QCOMPARE(sub_overflow(Int(min/2 + 1), Int(min/2), &r), false);
- QCOMPARE(r, Int(1));
- QCOMPARE(sub_overflow(Int(min/2), Int(min/2 + 1), &r), !min);
+ ADD_COMPARE_NONOVF(min/2 - 1, min/2 + 1, min / 2 * 2);
+ else
+ ADD_COMPARE_OVF(min/2 - 1, min/2 + 1);
+ SUB_COMPARE_NONOVF(min/2 - 1, min/2 + 1, -2);
+ SUB_COMPARE_NONOVF(min/2 + 1, min/2, 1);
if (min)
- QCOMPARE(r, Int(-1));
+ SUB_COMPARE_NONOVF(min/2, min/2 + 1, -1);
+ else
+ SUB_COMPARE_OVF(min/2, min/2 + 1);
// more than half
- QCOMPARE(add_overflow(Int(max/4 * 3), Int(max/4), &r), false);
- QCOMPARE(r, Int(max / 4 * 4));
+ ADD_COMPARE_NONOVF(max/4 * 3, max/4, max / 4 * 4);
// max
- QCOMPARE(add_overflow(max, Int(0), &r), false);
- QCOMPARE(r, max);
- QCOMPARE(sub_overflow(max, Int(0), &r), false);
- QCOMPARE(r, max);
- QCOMPARE(add_overflow(Int(0), max, &r), false);
- QCOMPARE(r, max);
- QCOMPARE(sub_overflow(Int(0), max, &r), !min);
+ ADD_COMPARE_NONOVF(max, 0, max);
+ SUB_COMPARE_NONOVF(max, 0, max);
+ ADD_COMPARE_NONOVF(0, max, max);
if (min)
- QCOMPARE(r, Int(-max));
-
- QCOMPARE(add_overflow(min, Int(0), &r), false);
- QCOMPARE(r, min);
- QCOMPARE(sub_overflow(min, Int(0), &r), false);
- QCOMPARE(r, min);
- QCOMPARE(add_overflow(Int(0), min, &r), false);
- QCOMPARE(r, min);
- QCOMPARE(sub_overflow(Int(0), Int(min+1), &r), !min);
+ SUB_COMPARE_NONOVF(0, max, -max);
+ else
+ SUB_COMPARE_OVF(0, max);
+
+ ADD_COMPARE_NONOVF(min, 0, min);
+ SUB_COMPARE_NONOVF(min, 0, min);
+ ADD_COMPARE_NONOVF(0, min, min);
if (min)
- QCOMPARE(r, Int(-(min+1)));
+ SUB_COMPARE_NONOVF(0, min+1, -(min+1));
+ else
+ SUB_COMPARE_OVF(0, min+1);
// 64-bit issues
- if (max > std::numeric_limits<uint>::max()) {
- QCOMPARE(add_overflow(Int(std::numeric_limits<uint>::max()), Int(std::numeric_limits<uint>::max()), &r), false);
- QCOMPARE(r, Int(2 * Int(std::numeric_limits<uint>::max())));
- QCOMPARE(sub_overflow(Int(std::numeric_limits<uint>::max()), Int(std::numeric_limits<uint>::max()), &r), false);
- QCOMPARE(r, Int(0));
+ if constexpr (max > std::numeric_limits<uint>::max()) {
+ ADD_COMPARE_NONOVF(std::numeric_limits<uint>::max(), std::numeric_limits<uint>::max(), 2 * Int(std::numeric_limits<uint>::max()));
+ SUB_COMPARE_NONOVF(std::numeric_limits<uint>::max(), std::numeric_limits<uint>::max(), 0);
}
- if (min && min < -Int(std::numeric_limits<uint>::max())) {
- QCOMPARE(add_overflow(Int(-Int(std::numeric_limits<uint>::max())), Int(-Int(std::numeric_limits<uint>::max())), &r), false);
- QCOMPARE(r, Int(-2 * Int(std::numeric_limits<uint>::max())));
- QCOMPARE(sub_overflow(Int(-Int(std::numeric_limits<uint>::max())), Int(-Int(std::numeric_limits<uint>::max())), &r), false);
- QCOMPARE(r, Int(0));
+ if constexpr (min != 0) {
+ if (qint64(min) < qint64(-std::numeric_limits<uint>::max())) {
+ ADD_COMPARE_NONOVF(-Int(std::numeric_limits<uint>::max()), -Int(std::numeric_limits<uint>::max()), -2 * Int(std::numeric_limits<uint>::max()));
+ SUB_COMPARE_NONOVF(-Int(std::numeric_limits<uint>::max()), -Int(std::numeric_limits<uint>::max()), 0);
+ }
}
// overflows past max
- QCOMPARE(add_overflow(max, Int(1), &r), true);
- QCOMPARE(add_overflow(Int(1), max, &r), true);
- QCOMPARE(add_overflow(Int(max/2 + 1), Int(max/2 + 1), &r), true);
- if (!min) {
- QCOMPARE(sub_overflow(Int(-max), Int(-2), &r), true);
- QCOMPARE(sub_overflow(Int(max/2 - 1), Int(max/2 + 1), &r), true);
+ ADD_COMPARE_OVF(max, 1);
+ ADD_COMPARE_OVF(1, max);
+ ADD_COMPARE_OVF(max/2 + 1, max/2 + 1);
+
+ // overflows past min
+ if constexpr (min != 0) {
+ ADD_COMPARE_OVF(-max, -2);
+ SUB_COMPARE_OVF(-max, 2);
+ SUB_COMPARE_OVF(-max/2 - 1, max/2 + 2);
+
+ SUB_COMPARE_OVF(min, 1);
+ SUB_COMPARE_OVF(1, min);
+ SUB_COMPARE_OVF(min/2 - 1, -Int(min/2));
+ ADD_COMPARE_OVF(min, -1);
+ ADD_COMPARE_OVF(-1, min);
}
- // overflows past min (in case of min == 0, repeats some tests above)
- if (min) {
- QCOMPARE(sub_overflow(min, Int(1), &r), true);
- QCOMPARE(sub_overflow(Int(1), min, &r), true);
- QCOMPARE(sub_overflow(Int(min/2 - 1), Int(-Int(min/2)), &r), true);
- QCOMPARE(add_overflow(min, Int(-1), &r), true);
- QCOMPARE(add_overflow(Int(-1), min, &r), true);
- }
+#undef ADD_COMPARE_NONOVF
+#undef ADD_COMPARE_OVF
+#undef SUB_COMPARE_NONOVF
+#undef SUB_COMPARE_OVF
#endif
}
@@ -552,77 +602,82 @@ template <typename Int> static void mulOverflow_template()
#if defined(Q_CC_MSVC) && Q_CC_MSVC < 1900
QSKIP("Test disabled, this test generates an Internal Compiler Error compiling");
#else
- const Int max = std::numeric_limits<Int>::max();
- const Int min = std::numeric_limits<Int>::min();
+ constexpr Int max = std::numeric_limits<Int>::max();
+ constexpr Int min = std::numeric_limits<Int>::min();
// for unsigned (even number of significant bits): mid2 = mid1 - 1
// for signed (odd number of significant bits): mid2 = mid1 / 2 - 1
- const Int mid1 = Int(Int(1) << sizeof(Int) * CHAR_BIT / 2);
- const Int mid2 = (std::numeric_limits<Int>::digits % 2 ? mid1 / 2 : mid1) - 1;
+ constexpr Int mid1 = Int(Int(1) << (sizeof(Int) * CHAR_BIT / 2));
+ constexpr Int mid2 = (std::numeric_limits<Int>::digits % 2 ? mid1 / 2 : mid1) - 1;
Int r;
+#define MUL_COMPARE_NONOVF(v1, v2, expected) \
+ do { \
+ QCOMPARE(qMulOverflow(Int(v1), Int(v2), &r), false); \
+ QCOMPARE(r, Int(expected)); \
+ QCOMPARE(qMulOverflow(Int(v1), (std::integral_constant<Int, v2>()), &r), false); \
+ QCOMPARE(r, Int(expected)); \
+ QCOMPARE(qMulOverflow<v2>(Int(v1), &r), false); \
+ QCOMPARE(r, Int(expected)); \
+ } while (false);
+#define MUL_COMPARE_OVF(v1, v2) \
+ do { \
+ QCOMPARE(qMulOverflow(Int(v1), Int(v2), &r), true); \
+ QCOMPARE(qMulOverflow(Int(v1), (std::integral_constant<Int, v2>()), &r), true); \
+ QCOMPARE(qMulOverflow<v2>(Int(v1), &r), true); \
+ } while (false);
+
// basic multiplications
- QCOMPARE(mul_overflow(Int(0), Int(0), &r), false);
- QCOMPARE(r, Int(0));
- QCOMPARE(mul_overflow(Int(1), Int(0), &r), false);
- QCOMPARE(r, Int(0));
- QCOMPARE(mul_overflow(Int(0), Int(1), &r), false);
- QCOMPARE(r, Int(0));
- QCOMPARE(mul_overflow(max, Int(0), &r), false);
- QCOMPARE(r, Int(0));
- QCOMPARE(mul_overflow(Int(0), max, &r), false);
- QCOMPARE(r, Int(0));
- QCOMPARE(mul_overflow(min, Int(0), &r), false);
- QCOMPARE(r, Int(0));
- QCOMPARE(mul_overflow(Int(0), min, &r), false);
- QCOMPARE(r, Int(0));
-
- QCOMPARE(mul_overflow(Int(1), Int(1), &r), false);
- QCOMPARE(r, Int(1));
- QCOMPARE(mul_overflow(Int(1), max, &r), false);
- QCOMPARE(r, max);
- QCOMPARE(mul_overflow(max, Int(1), &r), false);
- QCOMPARE(r, max);
- QCOMPARE(mul_overflow(Int(1), min, &r), false);
- QCOMPARE(r, min);
- QCOMPARE(mul_overflow(min, Int(1), &r), false);
- QCOMPARE(r, min);
+ MUL_COMPARE_NONOVF(0, 0, 0);
+ MUL_COMPARE_NONOVF(1, 0, 0);
+ MUL_COMPARE_NONOVF(0, 1, 0);
+ MUL_COMPARE_NONOVF(max, 0, 0);
+ MUL_COMPARE_NONOVF(0, max, 0);
+ MUL_COMPARE_NONOVF(min, 0, 0);
+ MUL_COMPARE_NONOVF(0, min, 0);
+ if constexpr (min != 0) {
+ MUL_COMPARE_NONOVF(0, -1, 0);
+ MUL_COMPARE_NONOVF(1, -1, -1);
+ MUL_COMPARE_NONOVF(max, -1, -max);
+ }
+
+ MUL_COMPARE_NONOVF(1, 1, 1);
+ MUL_COMPARE_NONOVF(1, max, max);
+ MUL_COMPARE_NONOVF(max, 1, max);
+ MUL_COMPARE_NONOVF(1, min, min);
+ MUL_COMPARE_NONOVF(min, 1, min);
// almost max
- QCOMPARE(mul_overflow(mid1, mid2, &r), false);
- QCOMPARE(r, Int(max - mid1 + 1));
- QCOMPARE(mul_overflow(Int(max / 2), Int(2), &r), false);
- QCOMPARE(r, Int(max & ~Int(1)));
- QCOMPARE(mul_overflow(Int(max / 4), Int(4), &r), false);
- QCOMPARE(r, Int(max & ~Int(3)));
- if (min) {
- QCOMPARE(mul_overflow(Int(-mid1), mid2, &r), false);
- QCOMPARE(r, Int(-max + mid1 - 1));
- QCOMPARE(mul_overflow(Int(-max / 2), Int(2), &r), false);
- QCOMPARE(r, Int(-max + 1));
- QCOMPARE(mul_overflow(Int(-max / 4), Int(4), &r), false);
- QCOMPARE(r, Int(-max + 3));
-
- QCOMPARE(mul_overflow(Int(-mid1), Int(mid2 + 1), &r), false);
- QCOMPARE(r, min);
- QCOMPARE(mul_overflow(mid1, Int(-mid2 - 1), &r), false);
- QCOMPARE(r, min);
+ MUL_COMPARE_NONOVF(mid1, mid2, max - mid1 + 1);
+ MUL_COMPARE_NONOVF(max / 2, 2, max & ~Int(1));
+ MUL_COMPARE_NONOVF(max / 4, 4, max & ~Int(3));
+ if constexpr (min != 0) {
+ MUL_COMPARE_NONOVF(-mid1, mid2, -max + mid1 - 1);
+ MUL_COMPARE_NONOVF(-max / 2, 2, -max + 1);
+ MUL_COMPARE_NONOVF(-max / 4, 4, -max + 3);
+
+ MUL_COMPARE_NONOVF(-mid1, mid2 + 1, min);
+ MUL_COMPARE_NONOVF(mid1, -mid2 - 1, min);
}
// overflows
- QCOMPARE(mul_overflow(max, Int(2), &r), true);
- QCOMPARE(mul_overflow(Int(max / 2), Int(3), &r), true);
- QCOMPARE(mul_overflow(mid1, Int(mid2 + 1), &r), true);
- QCOMPARE(mul_overflow(Int(max / 2 + 2), Int(2), &r), true);
- QCOMPARE(mul_overflow(Int(max - max / 2), Int(2), &r), true);
- QCOMPARE(mul_overflow(Int(1ULL << (std::numeric_limits<Int>::digits - 1)), Int(2), &r), true);
-
- if (min) {
- QCOMPARE(mul_overflow(min, Int(2), &r), true);
- QCOMPARE(mul_overflow(Int(min / 2), Int(3), &r), true);
- QCOMPARE(mul_overflow(Int(min / 2 - 1), Int(2), &r), true);
+ MUL_COMPARE_OVF(max, 2);
+ MUL_COMPARE_OVF(max / 2, 3);
+ MUL_COMPARE_OVF(mid1, mid2 + 1);
+ MUL_COMPARE_OVF(max / 2 + 2, 2);
+ MUL_COMPARE_OVF(max - max / 2, 2);
+ MUL_COMPARE_OVF(1ULL << (std::numeric_limits<Int>::digits - 1), 2);
+
+ if constexpr (min != 0) {
+ MUL_COMPARE_OVF(min, -1);
+ MUL_COMPARE_OVF(min, 2);
+ MUL_COMPARE_OVF(min / 2, 3);
+ MUL_COMPARE_OVF(min / 2 - 1, 2);
}
+
+#undef MUL_COMPARE_NONOVF
+#undef MUL_COMPARE_OVF
#endif
}
@@ -657,7 +712,7 @@ void tst_QNumeric::mulOverflow()
if (size == -32)
MulOverflowDispatch<qint32>()();
if (size == -64) {
-#if QT_POINTER_SIZE == 8
+#if QT_POINTER_SIZE == 8 || defined(Q_INTRINSIC_MUL_OVERFLOW64)
MulOverflowDispatch<qint64>()();
#else
QFAIL("128-bit multiplication not supported on this platform");
@@ -671,28 +726,28 @@ void tst_QNumeric::signedOverflow()
const int maxInt = std::numeric_limits<int>::max();
int r;
- QCOMPARE(add_overflow(minInt + 1, int(-1), &r), false);
- QCOMPARE(add_overflow(minInt, int(-1), &r), true);
- QCOMPARE(add_overflow(minInt, minInt, &r), true);
- QCOMPARE(add_overflow(maxInt - 1, int(1), &r), false);
- QCOMPARE(add_overflow(maxInt, int(1), &r), true);
- QCOMPARE(add_overflow(maxInt, maxInt, &r), true);
-
- QCOMPARE(sub_overflow(minInt + 1, int(1), &r), false);
- QCOMPARE(sub_overflow(minInt, int(1), &r), true);
- QCOMPARE(sub_overflow(minInt, maxInt, &r), true);
- QCOMPARE(sub_overflow(maxInt - 1, int(-1), &r), false);
- QCOMPARE(sub_overflow(maxInt, int(-1), &r), true);
- QCOMPARE(sub_overflow(maxInt, minInt, &r), true);
-
- QCOMPARE(mul_overflow(minInt, int(1), &r), false);
- QCOMPARE(mul_overflow(minInt, int(-1), &r), true);
- QCOMPARE(mul_overflow(minInt, int(2), &r), true);
- QCOMPARE(mul_overflow(minInt, minInt, &r), true);
- QCOMPARE(mul_overflow(maxInt, int(1), &r), false);
- QCOMPARE(mul_overflow(maxInt, int(-1), &r), false);
- QCOMPARE(mul_overflow(maxInt, int(2), &r), true);
- QCOMPARE(mul_overflow(maxInt, maxInt, &r), true);
+ QCOMPARE(qAddOverflow(minInt + 1, int(-1), &r), false);
+ QCOMPARE(qAddOverflow(minInt, int(-1), &r), true);
+ QCOMPARE(qAddOverflow(minInt, minInt, &r), true);
+ QCOMPARE(qAddOverflow(maxInt - 1, int(1), &r), false);
+ QCOMPARE(qAddOverflow(maxInt, int(1), &r), true);
+ QCOMPARE(qAddOverflow(maxInt, maxInt, &r), true);
+
+ QCOMPARE(qSubOverflow(minInt + 1, int(1), &r), false);
+ QCOMPARE(qSubOverflow(minInt, int(1), &r), true);
+ QCOMPARE(qSubOverflow(minInt, maxInt, &r), true);
+ QCOMPARE(qSubOverflow(maxInt - 1, int(-1), &r), false);
+ QCOMPARE(qSubOverflow(maxInt, int(-1), &r), true);
+ QCOMPARE(qSubOverflow(maxInt, minInt, &r), true);
+
+ QCOMPARE(qMulOverflow(minInt, int(1), &r), false);
+ QCOMPARE(qMulOverflow(minInt, int(-1), &r), true);
+ QCOMPARE(qMulOverflow(minInt, int(2), &r), true);
+ QCOMPARE(qMulOverflow(minInt, minInt, &r), true);
+ QCOMPARE(qMulOverflow(maxInt, int(1), &r), false);
+ QCOMPARE(qMulOverflow(maxInt, int(-1), &r), false);
+ QCOMPARE(qMulOverflow(maxInt, int(2), &r), true);
+ QCOMPARE(qMulOverflow(maxInt, maxInt, &r), true);
}
QTEST_APPLESS_MAIN(tst_QNumeric)