diff options
author | Alexandru Croitor <alexandru.croitor@qt.io> | 2019-10-14 17:46:16 +0200 |
---|---|---|
committer | Alexandru Croitor <alexandru.croitor@qt.io> | 2019-10-14 17:46:34 +0200 |
commit | 440286655e0ca271506cf7cc02ad0dbf4baef9ca (patch) | |
tree | 896fa81adb8b14a69355a3a6cf64d06ec8173c9a /tests/auto/corelib/global | |
parent | 1e27ad1697187549151657ba187928e439300db7 (diff) | |
parent | e164d61ca8263fc4b46fdd916e1ea77c7dd2b735 (diff) |
Merge remote-tracking branch 'origin/dev' into wip/cmake
Change-Id: I4a78428a8ea273b6960792e3b8043f816fa37fcf
Diffstat (limited to 'tests/auto/corelib/global')
3 files changed, 216 insertions, 114 deletions
diff --git a/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp b/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp index 5c7737085e..94f0afa5ed 100644 --- a/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp +++ b/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp @@ -41,7 +41,8 @@ private slots: void fuzzyCompare(); void ltgt_data(); void ltgt(); - void qNan(); + void qNaN(); + void infinity(); void float_cast(); void float_cast_data(); void promotionTests(); @@ -49,6 +50,9 @@ private slots: void arithOps(); void floatToFloat16(); void floatFromFloat16(); + void finite_data(); + void finite(); + void properties(); void limits(); }; @@ -103,6 +107,7 @@ void tst_qfloat16::ltgt_data() QTest::addColumn<float>("val2"); QTest::newRow("zero") << 0.0f << 0.0f; + QTest::newRow("-zero") << -0.0f << 0.0f; QTest::newRow("ten") << 10.0f << 10.0f; QTest::newRow("large") << 100000.0f << 100000.0f; QTest::newRow("small") << 0.0000001f << 0.0000001f; @@ -154,38 +159,66 @@ void tst_qfloat16::ltgt() # pragma GCC optimize "no-fast-math" #endif -void tst_qfloat16::qNan() +void tst_qfloat16::qNaN() { #if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ < 404) QSKIP("Non-conformant fast math mode is enabled, cannot run test"); #endif - qfloat16 nan = qQNaN(); - QVERIFY(!(0. > nan)); - QVERIFY(!(0. < nan)); + using Bounds = std::numeric_limits<qfloat16>; + const qfloat16 nan = Bounds::quiet_NaN(); + const qfloat16 zero(0), one(1); + QVERIFY(!(zero > nan)); + QVERIFY(!(zero < nan)); + QVERIFY(!(zero == nan)); QVERIFY(!qIsInf(nan)); QVERIFY(qIsNaN(nan)); - QVERIFY(qIsNaN(nan + 1.f)); + QVERIFY(qIsNaN(nan + one)); QVERIFY(qIsNaN(-nan)); - qfloat16 inf = qInf(); - QVERIFY(inf > qfloat16(0)); - QVERIFY(-inf < qfloat16(0)); - QVERIFY(!qIsNaN(inf)); - QVERIFY(qIsInf(inf)); - QVERIFY(qIsInf(-inf)); - QVERIFY(qIsInf(2.f*inf)); - QVERIFY(qIsInf(inf*2.f)); - // QTBUG-75812: QEMU/arm64 compiler over-optimizes, so flakily fails 1/inf == 0 :-( - if (qfloat16(9.785e-4f) == qfloat16(9.794e-4f)) - QCOMPARE(qfloat16(1.f) / inf, qfloat16(0.f)); #ifdef Q_CC_INTEL QEXPECT_FAIL("", "ICC optimizes zero * anything to zero", Continue); #endif - QVERIFY(qIsNaN(nan*0.f)); + QVERIFY(qIsNaN(nan * zero)); #ifdef Q_CC_INTEL QEXPECT_FAIL("", "ICC optimizes zero * anything to zero", Continue); #endif - QVERIFY(qIsNaN(inf*0.f)); - QVERIFY(qFuzzyCompare(qfloat16(1.f/inf), qfloat16(0.0))); + QVERIFY(qIsNaN(Bounds::infinity() * zero)); + + QVERIFY(!nan.isNormal()); + QVERIFY(!qIsFinite(nan)); + QVERIFY(!(nan == nan)); + QCOMPARE(nan, nan); // Despite the preceding + QCOMPARE(qFpClassify(nan), FP_NAN); +} + +void tst_qfloat16::infinity() +{ + const qfloat16 huge = std::numeric_limits<qfloat16>::infinity(); + const qfloat16 zero(0), one(1), two(2); + QVERIFY(huge > -huge); + QVERIFY(huge > zero); + QVERIFY(-huge < zero); + QCOMPARE(huge, huge); + QCOMPARE(-huge, -huge); + + // QTBUG-75812 - see overOptimized in the limits() test. + if (qfloat16(9.785e-4f) == qfloat16(9.794e-4f)) { + QCOMPARE(one / huge, zero); + QVERIFY(qFuzzyCompare(one / huge, zero)); // (same thing) + } + + QVERIFY(qIsInf(huge)); + QVERIFY(qIsInf(-huge)); + QVERIFY(qIsInf(two * huge)); + QVERIFY(qIsInf(huge * two)); + + QVERIFY(!huge.isNormal()); + QVERIFY(!(-huge).isNormal()); + QVERIFY(!qIsNaN(huge)); + QVERIFY(!qIsNaN(-huge)); + QVERIFY(!qIsFinite(huge)); + QVERIFY(!qIsFinite(-huge)); + QCOMPARE(qFpClassify(huge), FP_INFINITE); + QCOMPARE(qFpClassify(-huge), FP_INFINITE); } void tst_qfloat16::float_cast_data() @@ -366,10 +399,41 @@ static qfloat16 powf16(qfloat16 base, int raise) return answer; } -void tst_qfloat16::limits() +void tst_qfloat16::finite_data() +{ + using Bounds = std::numeric_limits<qfloat16>; + QTest::addColumn<qfloat16>("value"); + QTest::addColumn<int>("mode"); + + QTest::newRow("zero") << qfloat16(0) << FP_ZERO; + QTest::newRow("-zero") << -qfloat16(0) << FP_ZERO; + QTest::newRow("one") << qfloat16(1) << FP_NORMAL; + QTest::newRow("-one") << qfloat16(-1) << FP_NORMAL; + QTest::newRow("ten") << qfloat16(10) << FP_NORMAL; + QTest::newRow("-ten") << qfloat16(-10) << FP_NORMAL; + QTest::newRow("max") << Bounds::max() << FP_NORMAL; + QTest::newRow("lowest") << Bounds::lowest() << FP_NORMAL; + QTest::newRow("min") << Bounds::min() << FP_NORMAL; + QTest::newRow("-min") << -Bounds::min() << FP_NORMAL; + QTest::newRow("denorm_min") << Bounds::denorm_min() << FP_SUBNORMAL; + QTest::newRow("-denorm_min") << -Bounds::denorm_min() << FP_SUBNORMAL; +} + +void tst_qfloat16::finite() +{ + QFETCH(qfloat16, value); + QFETCH(int, mode); + QCOMPARE(value.isNormal(), mode != FP_SUBNORMAL); + QCOMPARE(value, value); // Fuzzy + QVERIFY(value == value); // Exact + QVERIFY(qIsFinite(value)); + QVERIFY(!qIsInf(value)); + QVERIFY(!qIsNaN(value)); + QCOMPARE(qFpClassify(value), mode); +} + +void tst_qfloat16::properties() { - // *NOT* using QCOMPARE() on finite qfloat16 values, since that uses fuzzy - // comparison, and we need exact here. using Bounds = std::numeric_limits<qfloat16>; QVERIFY(Bounds::is_specialized); QVERIFY(Bounds::is_signed); @@ -386,21 +450,22 @@ void tst_qfloat16::limits() QCOMPARE(Bounds::round_style, std::round_to_nearest); QCOMPARE(Bounds::radix, 2); // Untested: has_denorm_loss +} - // A few common values: +void tst_qfloat16::limits() // See also: qNaN() and infinity() +{ + // *NOT* using QCOMPARE() on finite qfloat16 values, since that uses fuzzy + // comparison, and we need exact here. + using Bounds = std::numeric_limits<qfloat16>; + + // A few useful values: const qfloat16 zero(0), one(1), ten(10); - QVERIFY(qIsFinite(zero)); - QVERIFY(!qIsInf(zero)); - QVERIFY(!qIsNaN(zero)); - QCOMPARE(qFpClassify(zero), FP_ZERO); - QVERIFY(qIsFinite(one)); - QVERIFY(!qIsInf(one)); - QCOMPARE(qFpClassify(one), FP_NORMAL); - QVERIFY(!qIsNaN(one)); - QVERIFY(qIsFinite(ten)); - QVERIFY(!qIsInf(ten)); - QVERIFY(!qIsNaN(ten)); - QCOMPARE(qFpClassify(ten), FP_NORMAL); + + // The specifics of minus zero: + // (IEEE 754 seems to want -zero < zero, but -0. == 0. and -0.f == 0.f in C++.) + QVERIFY(-zero <= zero); + QVERIFY(-zero == zero); + QVERIFY(!(-zero > zero)); // digits in the mantissa, including the implicit 1 before the binary dot at its left: QVERIFY(qfloat16(1 << (Bounds::digits - 1)) + one > qfloat16(1 << (Bounds::digits - 1))); @@ -436,12 +501,12 @@ void tst_qfloat16::limits() // How many digits are significant ? (Casts avoid linker errors ...) QCOMPARE(int(Bounds::digits10), 3); // 9.79e-4 has enough sigificant digits: qfloat16 below(9.785e-4f), above(9.794e-4f); -#if 0 // Sadly, the QEMU x-compile for arm64 "optimises" comparisons: - const bool overOptimised = false; +#if 0 // Sadly, the QEMU x-compile for arm64 "optimizes" comparisons: + const bool overOptimized = false; #else - const bool overOptimised = (below != above); - if (overOptimised) - QEXPECT_FAIL("", "Over-optimised on QEMU", Continue); + const bool overOptimized = (below != above); + if (overOptimized) + QEXPECT_FAIL("", "Over-optimized on ARM", Continue); #endif // (but it did, so should, pass everywhere else, confirming digits10 is indeed 3). QVERIFY(below == above); QCOMPARE(int(Bounds::max_digits10), 5); // we need 5 to distinguish these two: @@ -450,62 +515,26 @@ void tst_qfloat16::limits() // Actual limiting values of the type: const qfloat16 rose(one + Bounds::epsilon()); QVERIFY(rose > one); - if (overOptimised) - QEXPECT_FAIL("", "Over-optimised on QEMU", Continue); + if (overOptimized) + QEXPECT_FAIL("", "Over-optimized on ARM", Continue); QVERIFY(one + Bounds::epsilon() / rose == one); - QVERIFY(qIsInf(Bounds::infinity())); - QVERIFY(!qIsNaN(Bounds::infinity())); - QVERIFY(!qIsFinite(Bounds::infinity())); - QCOMPARE(Bounds::infinity(), Bounds::infinity()); - QCOMPARE(qFpClassify(Bounds::infinity()), FP_INFINITE); - - QVERIFY(Bounds::infinity() > -Bounds::infinity()); - QVERIFY(Bounds::infinity() > zero); - QVERIFY(qIsInf(-Bounds::infinity())); - QVERIFY(!qIsNaN(-Bounds::infinity())); - QVERIFY(!qIsFinite(-Bounds::infinity())); - QCOMPARE(-Bounds::infinity(), -Bounds::infinity()); - QCOMPARE(qFpClassify(-Bounds::infinity()), FP_INFINITE); - - QVERIFY(-Bounds::infinity() < zero); - QVERIFY(qIsNaN(Bounds::quiet_NaN())); - QVERIFY(!qIsInf(Bounds::quiet_NaN())); - QVERIFY(!qIsFinite(Bounds::quiet_NaN())); - QVERIFY(!(Bounds::quiet_NaN() == Bounds::quiet_NaN())); - QCOMPARE(Bounds::quiet_NaN(), Bounds::quiet_NaN()); - QCOMPARE(qFpClassify(Bounds::quiet_NaN()), FP_NAN); QVERIFY(Bounds::max() > zero); - QVERIFY(qIsFinite(Bounds::max())); - QVERIFY(!qIsInf(Bounds::max())); - QVERIFY(!qIsNaN(Bounds::max())); QVERIFY(qIsInf(Bounds::max() * rose)); - QCOMPARE(qFpClassify(Bounds::max()), FP_NORMAL); QVERIFY(Bounds::lowest() < zero); - QVERIFY(qIsFinite(Bounds::lowest())); - QVERIFY(!qIsInf(Bounds::lowest())); - QVERIFY(!qIsNaN(Bounds::lowest())); QVERIFY(qIsInf(Bounds::lowest() * rose)); - QCOMPARE(qFpClassify(Bounds::lowest()), FP_NORMAL); QVERIFY(Bounds::min() > zero); - QVERIFY(Bounds::min().isNormal()); QVERIFY(!(Bounds::min() / rose).isNormal()); - QVERIFY(qIsFinite(Bounds::min())); - QVERIFY(!qIsInf(Bounds::min())); - QVERIFY(!qIsNaN(Bounds::min())); - QCOMPARE(qFpClassify(Bounds::min()), FP_NORMAL); QVERIFY(Bounds::denorm_min() > zero); - QVERIFY(!Bounds::denorm_min().isNormal()); - QVERIFY(qIsFinite(Bounds::denorm_min())); - QVERIFY(!qIsInf(Bounds::denorm_min())); - QVERIFY(!qIsNaN(Bounds::denorm_min())); - if (overOptimised) - QEXPECT_FAIL("", "Over-optimised on QEMU", Continue); - QCOMPARE(Bounds::denorm_min() / rose, zero); - QCOMPARE(qFpClassify(Bounds::denorm_min()), FP_SUBNORMAL); + if (overOptimized) + QEXPECT_FAIL("", "Over-optimized on ARM", Continue); + QVERIFY(Bounds::denorm_min() / rose == zero); + if (overOptimized) + QEXPECT_FAIL("", "Over-optimized on ARM", Continue); + QVERIFY(-Bounds::denorm_min() / rose == -zero); } QTEST_APPLESS_MAIN(tst_qfloat16) diff --git a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp index 0a84b1fdd8..a6d600e125 100644 --- a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp +++ b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp @@ -42,7 +42,14 @@ class tst_QNumeric: public QObject private slots: void fuzzyCompare_data(); void fuzzyCompare(); - void qNanInf(); + void rawNaN_data(); + void rawNaN(); +#if QT_CONFIG(signaling_nan) + void distinctNaN(); +#endif + void generalNaN_data(); + void generalNaN(); + void infinity(); void classifyfp(); void floatDistance_data(); void floatDistance(); @@ -53,6 +60,8 @@ private slots: void mulOverflow_data(); void mulOverflow(); void signedOverflow(); +private: + void checkNaN(double nan); }; void tst_QNumeric::fuzzyCompare_data() @@ -92,44 +101,101 @@ void tst_QNumeric::fuzzyCompare() # pragma GCC optimize "no-fast-math" #endif -void tst_QNumeric::qNanInf() +void tst_QNumeric::checkNaN(double nan) { -#if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ < 404) - QSKIP("Non-conformant fast math mode is enabled, cannot run test"); -#endif - double nan = qQNaN(); +#define CHECKNAN(value) \ + do { \ + const double v = (value); \ + QCOMPARE(qFpClassify(v), FP_NAN); \ + QVERIFY(qIsNaN(v)); \ + QVERIFY(!qIsFinite(v)); \ + QVERIFY(!qIsInf(v)); \ + } while (0) + QVERIFY(!(0 > nan)); QVERIFY(!(0 < nan)); QVERIFY(!(0 == nan)); QVERIFY(!(nan == nan)); - QVERIFY(qIsNaN(nan)); - QVERIFY(qIsNaN(nan + 1)); - QVERIFY(qIsNaN(-nan)); - QVERIFY(qIsNaN(1.0 / nan)); - QVERIFY(qIsNaN(0.0 / nan)); - QVERIFY(qIsNaN(0.0 * nan)); + + CHECKNAN(nan); + CHECKNAN(nan + 1); + CHECKNAN(nan - 1); + CHECKNAN(-nan); + CHECKNAN(nan * 2.0); + CHECKNAN(nan / 2.0); + CHECKNAN(1.0 / nan); + CHECKNAN(0.0 / nan); + CHECKNAN(0.0 * nan); + + // When any NaN is expected, any NaN will do: QCOMPARE(nan, nan); QCOMPARE(nan, -nan); + QCOMPARE(nan, qQNaN()); +#undef CHECKNAN +} +void tst_QNumeric::rawNaN_data() +{ +#if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ < 404) + QSKIP("Non-conformant fast math mode is enabled, cannot run test"); +#endif + QTest::addColumn<double>("nan"); + + QTest::newRow("quiet") << qQNaN(); +#if QT_CONFIG(signaling_nan) + QTest::newRow("signaling") << qSNaN(); +#endif +} + +void tst_QNumeric::rawNaN() +{ + QFETCH(double, nan); + checkNaN(nan); +} + +#if QT_CONFIG(signaling_nan) +void tst_QNumeric::distinctNaN() +{ + const double qnan = qQNaN(); + const double snan = qSNaN(); + QVERIFY(memcmp(&qnan, &snan, sizeof(double)) != 0); +} +#endif + +void tst_QNumeric::generalNaN_data() +{ + QTest::addColumn<int>("most"); + QTest::addColumn<int>("next"); + QTest::addColumn<int>("least"); + // Every value with every bit of the exponent set is a NaN. + // Sign and mantissa can be anything without interfering with that. + // The 0x7f bits of most and the 0xf0 bits of next are the exponent. + + QTest::newRow("lowload") << 0x7f << 0xf0 << 1; + QTest::newRow("sign-lowload") << 0xff << 0xf0 << 1; + QTest::newRow("highload") << 0x7f << 0xf1 << 0; + QTest::newRow("sign-highload") << 0xff << 0xf1 << 0; +} + +void tst_QNumeric::generalNaN() +{ + QFETCH(int, most); + QFETCH(int, next); + QFETCH(int, least); + double nan; Q_STATIC_ASSERT(sizeof(double) == 8); #ifdef Q_LITTLE_ENDIAN - const uchar bytes[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f }; + const uchar bytes[] = { uchar(least), 0, 0, 0, 0, 0, uchar(next), uchar(most) }; #else - const uchar bytes[] = { 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; + const uchar bytes[] = { uchar(most), uchar(next), 0, 0, 0, 0, 0, uchar(least) }; #endif memcpy(&nan, bytes, 8); - QVERIFY(!qIsFinite(nan)); - QVERIFY(!qIsInf(nan)); - QVERIFY(qIsNaN(nan)); - QVERIFY(qIsNaN(-nan)); - QVERIFY(!(nan == nan)); - QVERIFY(qIsNaN(0.0 * nan)); - QCOMPARE(qFpClassify(nan), FP_NAN); - QCOMPARE(nan, nan); - QCOMPARE(nan, -nan); - QCOMPARE(nan, qQNaN()); + checkNaN(nan); +} - double inf = qInf(); +void tst_QNumeric::infinity() +{ + const double inf = qInf(); QVERIFY(inf > 0); QVERIFY(-inf < 0); QVERIFY(qIsInf(inf)); @@ -138,16 +204,23 @@ void tst_QNumeric::qNanInf() QVERIFY(qIsInf(-inf)); QVERIFY(qIsInf(inf + 1)); QVERIFY(qIsInf(inf - 1)); + QVERIFY(qIsInf(-inf - 1)); + QVERIFY(qIsInf(-inf + 1)); QVERIFY(qIsInf(inf * 2.0)); + QVERIFY(qIsInf(-inf * 2.0)); QVERIFY(qIsInf(inf / 2.0)); + QVERIFY(qIsInf(-inf / 2.0)); QVERIFY(qFuzzyCompare(1.0 / inf, 0.0)); QCOMPARE(1.0 / inf, 0.0); + QVERIFY(qFuzzyCompare(1.0 / -inf, 0.0)); + QCOMPARE(1.0 / -inf, 0.0); QVERIFY(qIsNaN(0.0 * inf)); + QVERIFY(qIsNaN(0.0 * -inf)); } void tst_QNumeric::classifyfp() { - QCOMPARE(qFpClassify(qQNaN()), FP_NAN); + // NaNs already handled, see checkNaN()'s callers. QCOMPARE(qFpClassify(qInf()), FP_INFINITE); QCOMPARE(qFpClassify(-qInf()), FP_INFINITE); diff --git a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp index e238be1de3..6f9dcc08f9 100644 --- a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp +++ b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp @@ -320,7 +320,7 @@ void tst_QRandomGenerator::generate32_data() QTest::newRow("fixed") << (RandomValue32 & RandomDataMask); QTest::newRow("global") << 0U; #ifdef QT_BUILD_INTERNAL - if (qt_has_hwrng()) + if (qHasHwrng()) QTest::newRow("hwrng") << uint(UseSystemRNG); QTest::newRow("system") << uint(UseSystemRNG | SkipHWRNG); # ifdef HAVE_FALLBACK_ENGINE @@ -755,7 +755,7 @@ void tst_QRandomGenerator::stdUniformIntDistribution_data() auto newRow = [&](quint32 max) { #ifdef QT_BUILD_INTERNAL - if (qt_has_hwrng()) + if (qHasHwrng()) QTest::addRow("hwrng:%u", max) << uint(UseSystemRNG) << max; QTest::addRow("system:%u", max) << uint(UseSystemRNG | SkipHWRNG) << max; # ifdef HAVE_FALLBACK_ENGINE @@ -868,7 +868,7 @@ void tst_QRandomGenerator::stdUniformRealDistribution_data() auto newRow = [&](double min, double sup) { #ifdef QT_BUILD_INTERNAL - if (qt_has_hwrng()) + if (qHasHwrng()) QTest::addRow("hwrng:%g-%g", min, sup) << uint(UseSystemRNG) << min << sup; QTest::addRow("system:%g-%g", min, sup) << uint(UseSystemRNG | SkipHWRNG) << min << sup; # ifdef HAVE_FALLBACK_ENGINE |