diff options
Diffstat (limited to 'tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp')
-rw-r--r-- | tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp | 341 |
1 files changed, 303 insertions, 38 deletions
diff --git a/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp b/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp index 82ad6b1c38..5f1ff67316 100644 --- a/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp +++ b/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp @@ -1,34 +1,13 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Copyright (C) 2016 by Southwest Research Institute (R) -** 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) 2021 The Qt Company Ltd. +// Copyright (C) 2016 by Southwest Research Institute (R) +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> #include <QFloat16> +#include <QMetaType> +#include <QTextStream> + +#include <private/qcomparisontesthelper_p.h> #include <math.h> @@ -41,8 +20,14 @@ class tst_qfloat16: public QObject Q_OBJECT private slots: + void compareCompiles(); + void relationalOperatorsAreConstexpr(); + void ordering_data(); + void ordering(); void fuzzyCompare_data(); void fuzzyCompare(); + void fuzzyIsNull_data(); + void fuzzyIsNull(); void ltgt_data(); void ltgt(); void qNaN(); @@ -64,8 +49,191 @@ private slots: void properties(); void limits(); void mantissaOverflow(); + void dataStream(); + void textStream(); }; +void tst_qfloat16::compareCompiles() +{ + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, float>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, double>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, long double>(); +#if QFLOAT16_IS_NATIVE + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, qfloat16::NativeType>(); +#endif + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, int>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, qint8>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, quint8>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, qint16>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, quint16>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, char16_t>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, long>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, unsigned long>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, wchar_t>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, qint32>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, quint32>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, qint64>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, quint64>(); +#ifdef QT_SUPPORTS_INT128 + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, qint128>(); + QTestPrivate::testAllComparisonOperatorsCompile<qfloat16, quint128>(); +#endif +} + +void tst_qfloat16::relationalOperatorsAreConstexpr() +{ +#if QFLOAT16_IS_NATIVE + +#define CHECK_CONSTEXPR(Type) \ + do { \ + constexpr qfloat16 lhs = qfloat16(0.0f); \ + constexpr Type rhs = 1; \ + static_assert(lhs < rhs); \ + static_assert(rhs >= lhs); \ + } while (false) + + CHECK_CONSTEXPR(qfloat16); + CHECK_CONSTEXPR(float); + CHECK_CONSTEXPR(double); + CHECK_CONSTEXPR(long double); + CHECK_CONSTEXPR(qfloat16::NativeType); + CHECK_CONSTEXPR(qint8); + CHECK_CONSTEXPR(quint8); + CHECK_CONSTEXPR(qint16); + CHECK_CONSTEXPR(quint16); + CHECK_CONSTEXPR(qint32); + CHECK_CONSTEXPR(quint32); + CHECK_CONSTEXPR(long); + CHECK_CONSTEXPR(unsigned long); + CHECK_CONSTEXPR(qint64); + CHECK_CONSTEXPR(quint64); +#ifdef QT_SUPPORTS_INT128 + CHECK_CONSTEXPR(qint128); + CHECK_CONSTEXPR(quint128); +#endif + +#undef CHECK_CONSTEXPR + +#else + QSKIP("This check is only relevant for native float16 types"); +#endif // QFLOAT16_IS_NATIVE +} + +void tst_qfloat16::ordering_data() +{ + QTest::addColumn<float>("left"); + QTest::addColumn<float>("right"); + + auto row = [](float left, float right) { + QTest::addRow("%f_vs_%f", left, right) << left << right; + }; + + row(0.0f, 0.0f); + row(0.000001f, 0.0f); + row(0.0f, 0.000001f); + row(-1.000001f, 1.000001f); + const float nan = std::numeric_limits<float>::quiet_NaN(); + const float inf = std::numeric_limits<float>::infinity(); + row(nan, nan); + row(nan, inf); + row(inf, nan); + row(-inf, nan); + row(nan, -inf); + row(-inf, inf); + row(inf, -inf); + row(-inf, 0.0f); + row(0.0f, inf); + row(0.0f, nan); + row(nan, 0.0f); + row(2.0f, 314.159f); + row(-314.159f, 2.0f); + row(-2.0f, 314.159f); + row(nan, 314.159f); + row(-314.159f, inf); + row(-inf, 314.159f); + row(2.0f, -inf); + row(-2.0f, nan); + row(-inf, -2.0f); + + // testing with values outside qfloat16 range + row(0.0f, 13e5f); + // generateRow(inf, 13e5f); // fails qfloat16 vs qfloat16 and qfloat16 vs int (QTBUG-118193) + row(0.0f, -13e5f); + // generateRow(-inf, -13e5f); // fails qfloat16 vs qfloat16 and qfloat16 vs int (QTBUG-118193) +} + +void tst_qfloat16::ordering() +{ + QFETCH(float, left); + QFETCH(float, right); + + const auto expectedOrder = Qt::compareThreeWay(left, right); + const auto lhs = qfloat16(left); + +#define POSTCHECK(msg) \ + if (QTest::currentTestFailed()) { qDebug(msg); return; } + +#define CHECK_FP(RHS) \ + do { \ + QTestPrivate::testAllComparisonOperators(lhs, static_cast<RHS>(right), expectedOrder); \ + POSTCHECK("qfloat16 vs " #RHS " comparison failed") \ + } while (false) \ + /* END */ + + CHECK_FP(qfloat16); + CHECK_FP(float); + CHECK_FP(double); + CHECK_FP(long double); + +#undef CHECK_FP + + auto check_int = [=](auto rhs) { + // check that we're in range before converting, otherwise + // [conv.fpint]/1 says it would be UB + using RHS = decltype(rhs); + if (right > double(std::numeric_limits<RHS>::max())) + return; + if (auto min = std::numeric_limits<RHS>::min(); min != 0 && right < double(min)) + return; + rhs = RHS(right); + const auto expectedRes = Qt::compareThreeWay(left, rhs); + QTestPrivate::testAllComparisonOperators(lhs, rhs, expectedRes); + }; +#define CHECK_INT(RHS) \ + do { \ + check_int(static_cast<RHS>(0)); \ + POSTCHECK("qfloat16 vs " #RHS " comparison failed") \ + } while (false) \ + /* END */ + + if (qIsFinite(right)) { + CHECK_INT(int); + CHECK_INT(qint8); + CHECK_INT(signed char); + CHECK_INT(qint16); + CHECK_INT(qint32); + CHECK_INT(qint64); +#if QT_SUPPORTS_INT128 + CHECK_INT(qint128); +#endif + if (right >= 0) { + CHECK_INT(unsigned int); + CHECK_INT(quint8); + CHECK_INT(unsigned char); + CHECK_INT(quint16); + CHECK_INT(quint32); + CHECK_INT(quint64); + #if QT_SUPPORTS_INT128 + CHECK_INT(quint128); + #endif + } + } + +#undef CHECK_INT +#undef POSTCHECK +} + void tst_qfloat16::fuzzyCompare_data() { QTest::addColumn<qfloat16>("val1"); @@ -111,6 +279,33 @@ void tst_qfloat16::fuzzyCompare() } } +void tst_qfloat16::fuzzyIsNull_data() +{ + QTest::addColumn<qfloat16>("value"); + QTest::addColumn<bool>("isNull"); + using Bounds = std::numeric_limits<qfloat16>; + const qfloat16 one(1), huge(1000), tiny(0.00976f); + + QTest::newRow("zero") << qfloat16(0.0f) << true; + QTest::newRow("min") << Bounds::min() << true; + QTest::newRow("denorm_min") << Bounds::denorm_min() << true; + QTest::newRow("tiny") << tiny << true; + + QTest::newRow("deci") << qfloat16(.1) << false; + QTest::newRow("one") << one << false; + QTest::newRow("ten") << qfloat16(10) << false; + QTest::newRow("huge") << huge << false; +} + +void tst_qfloat16::fuzzyIsNull() +{ + QFETCH(qfloat16, value); + QFETCH(bool, isNull); + + QCOMPARE(::qFuzzyIsNull(value), isNull); + QCOMPARE(::qFuzzyIsNull(-value), isNull); +} + void tst_qfloat16::ltgt_data() { QTest::addColumn<float>("val1"); @@ -184,13 +379,7 @@ void tst_qfloat16::qNaN() QVERIFY(qIsNaN(nan)); QVERIFY(qIsNaN(nan + one)); QVERIFY(qIsNaN(-nan)); -#ifdef Q_CC_INTEL - QEXPECT_FAIL("", "ICC optimizes zero * anything to zero", Continue); -#endif QVERIFY(qIsNaN(nan * zero)); -#ifdef Q_CC_INTEL - QEXPECT_FAIL("", "ICC optimizes zero * anything to zero", Continue); -#endif QVERIFY(qIsNaN(Bounds::infinity() * zero)); QVERIFY(!nan.isNormal()); @@ -303,7 +492,7 @@ void tst_qfloat16::promotionTests() QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)*1)); QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)/1)); - QCOMPARE(QString::number(1.f),QString::number(qfloat16(1.f))); + QCOMPARE(QString::number(1.f),QString::number(double(qfloat16(1.f)))); } void tst_qfloat16::arithOps_data() @@ -511,14 +700,35 @@ void tst_qfloat16::properties() QVERIFY(Bounds::is_signed); QVERIFY(!Bounds::is_integer); QVERIFY(!Bounds::is_exact); + + // While we'd like to check for __STDC_IEC_559__, as per ISO/IEC 9899:2011 + // Annex F (C11, normative for C++11), there are a few corner cases regarding + // denormals where GHS compiler is relying hardware behavior that is not IEC + // 559 compliant. + + // On GHS the compiler reports std::numeric_limits<float>::is_iec559 as false. + // and the same supposed to be for qfloat16. +#if !defined(Q_CC_GHS) QVERIFY(Bounds::is_iec559); +#endif //Q_CC_GHS +#if QT_CONFIG(signaling_nan) + // Technically, presence of NaN and infinities are implied from the above check, but that checkings GHS compiler complies. + QVERIFY(Bounds::has_infinity && Bounds::has_quiet_NaN && Bounds::has_signaling_NaN); +#endif QVERIFY(Bounds::is_bounded); QVERIFY(!Bounds::is_modulo); QVERIFY(!Bounds::traps); QVERIFY(Bounds::has_infinity); QVERIFY(Bounds::has_quiet_NaN); +#if QT_CONFIG(signaling_nan) QVERIFY(Bounds::has_signaling_NaN); +#endif +#if !defined(Q_CC_GHS) QCOMPARE(Bounds::has_denorm, std::denorm_present); +#else + // For GHS compiler the "denorm_indeterminite" is the expected return value. + QCOMPARE(Bounds::has_denorm, std::denorm_indeterminate); +#endif // Q_CC_GHS QCOMPARE(Bounds::round_style, std::round_to_nearest); QCOMPARE(Bounds::radix, 2); // Untested: has_denorm_loss @@ -605,12 +815,67 @@ void tst_qfloat16::mantissaOverflow() float f; memcpy(&f, &in, 4); - qfloat16 f16 = f; + qfloat16 f16 = qfloat16(f); qfloat16 f16s[1]; qFloatToFloat16(f16s, &f, 1); QCOMPARE(f16, f16s[0]); QVERIFY(qIsNaN(f16)); } +void tst_qfloat16::dataStream() +{ + QByteArray ba; + QDataStream ds(&ba, QIODevice::ReadWrite); + ds << qfloat16(1.5) << qfloat16(-1); + QCOMPARE(ba.size(), 4); + QCOMPARE(ds.status(), QDataStream::Ok); + QCOMPARE(ba, QByteArray("\x3e\0\xbc\0", 4)); + + ds.device()->seek(0); + ds.resetStatus(); + ds.setByteOrder(QDataStream::LittleEndian); + ds << qfloat16(0) << qfloat16(-1); + QCOMPARE(ds.status(), QDataStream::Ok); + QCOMPARE(ba, QByteArray("\0\0\0\xbc", 4)); + + ds.device()->seek(0); + ds.resetStatus(); + qfloat16 zero = 1; + ds >> zero; + QCOMPARE(ds.status(), QDataStream::Ok); + QCOMPARE(zero, qfloat16(0)); + + ds.device()->seek(0); + ds.resetStatus(); + QMetaType mt = QMetaType(QMetaType::Float16); + QVERIFY(mt.save(ds, &zero)); + + ds.device()->seek(0); + ds.resetStatus(); + zero = -1; + QVERIFY(mt.load(ds, &zero)); + QCOMPARE(zero, qfloat16(0)); +} + +void tst_qfloat16::textStream() +{ + QString buffer; + { + QTextStream ts(&buffer); + ts << qfloat16(0) << Qt::endl << qfloat16(1.5); + QCOMPARE(ts.status(), QTextStream::Ok); + } + QCOMPARE(buffer, "0\n1.5"); + + { + QTextStream ts(&buffer); + qfloat16 zero = qfloat16(-2.5), threehalves = 1234; + ts >> zero >> threehalves; + QCOMPARE(ts.status(), QTextStream::Ok); + QCOMPARE(zero, qfloat16(0)); + QCOMPARE(threehalves, 1.5); + } +} + QTEST_APPLESS_MAIN(tst_qfloat16) #include "tst_qfloat16.moc" |