From e37001aad7f6e4bbad250addba033f1eaf97d566 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Wed, 31 Jul 2013 15:43:09 +0200 Subject: Say hello to qFloatDistance() This function is useful if a floating point comparison requires a certain precision. The return value can be considered as the precision. For instance, if you want to compare two 32-bit floating point values and all you need is a 24-bit precision, you can use this function like this: if (qFloatDistance(a,b) < (1 << 7)) { // The last 7 bits are not // significant // precise enough } Task-number: QTBUG-32632 Change-Id: I020a58d2f9f9452ac3c510b4bb560dc806f0d93c Reviewed-by: Shawn Rutledge Reviewed-by: Thiago Macieira --- .../auto/corelib/global/qnumeric/tst_qnumeric.cpp | 93 ++++++++++++++++++++++ 1 file changed, 93 insertions(+) (limited to 'tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp') diff --git a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp index 20f99e9191..36e01a0ccd 100644 --- a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp +++ b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp @@ -44,6 +44,7 @@ #include #include +#include class tst_QNumeric: public QObject { @@ -53,6 +54,10 @@ private slots: void fuzzyCompare_data(); void fuzzyCompare(); void qNan(); + void floatDistance_data(); + void floatDistance(); + void floatDistance_double_data(); + void floatDistance_double(); }; void tst_QNumeric::fuzzyCompare_data() @@ -121,5 +126,93 @@ void tst_QNumeric::qNan() QVERIFY(qFuzzyCompare(1/inf, 0.0)); } +void tst_QNumeric::floatDistance_data() +{ + QTest::addColumn("val1"); + QTest::addColumn("val2"); + QTest::addColumn("expectedDistance"); + + // exponent: 8 bits + // mantissa: 23 bits + const quint32 number_of_denormals = (1 << 23) - 1; // Set to 0 if denormals are not included + + quint32 _0_to_1 = quint32((1 << 23) * 126 + 1 + number_of_denormals); // We need +1 to include the 0 + quint32 _1_to_2 = quint32(1 << 23); + + // We don't need +1 because FLT_MAX has all bits set in the mantissa. (Thus mantissa + // have not wrapped back to 0, which would be the case for 1 in _0_to_1 + quint32 _0_to_FLT_MAX = quint32((1 << 23) * 254) + number_of_denormals; + + quint32 _0_to_FLT_MIN = 1 + number_of_denormals; + QTest::newRow("[0,FLT_MIN]") << 0.F << FLT_MIN << _0_to_FLT_MIN; + QTest::newRow("[0,FLT_MAX]") << 0.F << FLT_MAX << _0_to_FLT_MAX; + QTest::newRow("[1,1.5]") << 1.0F << 1.5F << quint32(1 << 22); + QTest::newRow("[0,1]") << 0.F << 1.0F << _0_to_1; + QTest::newRow("[0.5,1]") << 0.5F << 1.0F << quint32(1 << 23); + QTest::newRow("[1,2]") << 1.F << 2.0F << _1_to_2; + QTest::newRow("[-1,+1]") << -1.F << +1.0F << 2 * _0_to_1; + QTest::newRow("[-1,0]") << -1.F << 0.0F << _0_to_1; + QTest::newRow("[-1,FLT_MAX]") << -1.F << FLT_MAX << _0_to_1 + _0_to_FLT_MAX; + QTest::newRow("[-2,-1") << -2.F << -1.F << _1_to_2; + QTest::newRow("[-1,-2") << -1.F << -2.F << _1_to_2; + QTest::newRow("[FLT_MIN,FLT_MAX]") << FLT_MIN << FLT_MAX << _0_to_FLT_MAX - _0_to_FLT_MIN; + QTest::newRow("[-FLT_MAX,FLT_MAX]") << -FLT_MAX << FLT_MAX << (2*_0_to_FLT_MAX); + float denormal = FLT_MIN; + denormal/=2.0F; + QTest::newRow("denormal") << 0.F << denormal << _0_to_FLT_MIN/2; +} + +void tst_QNumeric::floatDistance() +{ + QFETCH(float, val1); + QFETCH(float, val2); + QFETCH(quint32, expectedDistance); + QCOMPARE(qFloatDistance(val1, val2), expectedDistance); +} + +void tst_QNumeric::floatDistance_double_data() +{ + QTest::addColumn("val1"); + QTest::addColumn("val2"); + QTest::addColumn("expectedDistance"); + + // exponent: 11 bits + // mantissa: 52 bits + const quint64 number_of_denormals = (Q_UINT64_C(1) << 52) - 1; // Set to 0 if denormals are not included + + quint64 _0_to_1 = (Q_UINT64_C(1) << 52) * ((1 << (11-1)) - 2) + 1 + number_of_denormals; // We need +1 to include the 0 + quint64 _1_to_2 = Q_UINT64_C(1) << 52; + + // We don't need +1 because DBL_MAX has all bits set in the mantissa. (Thus mantissa + // have not wrapped back to 0, which would be the case for 1 in _0_to_1 + quint64 _0_to_DBL_MAX = quint64((Q_UINT64_C(1) << 52) * ((1 << 11) - 2)) + number_of_denormals; + + quint64 _0_to_DBL_MIN = 1 + number_of_denormals; + QTest::newRow("[0,DBL_MIN]") << 0.0 << DBL_MIN << _0_to_DBL_MIN; + QTest::newRow("[0,DBL_MAX]") << 0.0 << DBL_MAX << _0_to_DBL_MAX; + QTest::newRow("[1,1.5]") << 1.0 << 1.5 << (Q_UINT64_C(1) << 51); + QTest::newRow("[0,1]") << 0.0 << 1.0 << _0_to_1; + QTest::newRow("[0.5,1]") << 0.5 << 1.0 << (Q_UINT64_C(1) << 52); + QTest::newRow("[1,2]") << 1.0 << 2.0 << _1_to_2; + QTest::newRow("[-1,+1]") << -1.0 << +1.0 << 2 * _0_to_1; + QTest::newRow("[-1,0]") << -1.0 << 0.0 << _0_to_1; + QTest::newRow("[-1,DBL_MAX]") << -1.0 << DBL_MAX << _0_to_1 + _0_to_DBL_MAX; + QTest::newRow("[-2,-1") << -2.0 << -1.0 << _1_to_2; + QTest::newRow("[-1,-2") << -1.0 << -2.0 << _1_to_2; + QTest::newRow("[DBL_MIN,DBL_MAX]") << DBL_MIN << DBL_MAX << _0_to_DBL_MAX - _0_to_DBL_MIN; + QTest::newRow("[-DBL_MAX,DBL_MAX]") << -DBL_MAX << DBL_MAX << (2*_0_to_DBL_MAX); + double denormal = DBL_MIN; + denormal/=2.0; + QTest::newRow("denormal") << 0.0 << denormal << _0_to_DBL_MIN/2; +} + +void tst_QNumeric::floatDistance_double() +{ + QFETCH(double, val1); + QFETCH(double, val2); + QFETCH(quint64, expectedDistance); + QCOMPARE(qFloatDistance(val1, val2), expectedDistance); +} + QTEST_APPLESS_MAIN(tst_QNumeric) #include "tst_qnumeric.moc" -- cgit v1.2.3