Rearrange tst_QNumeric's tests for infinity and (quiet) NaN

Separate quiet NaN from infinity and expand the nan-with-payload test
to a general test that bits outside the exponent don't break qIsNan().
Generally test more thoroughly and systematically.
Tests for signalling NaN shall follow.

Change-Id: Ib35dabacc8ebcc9a0761df38f6f419f0398d0e20
Reviewed-by: Erik Verbruggen <erik.verbruggen@me.com>
bb10
Edward Welbourne 2019-09-18 11:32:50 +02:00
parent 2dfeea921b
commit 35aec918c1
1 changed files with 88 additions and 30 deletions

View File

@ -42,7 +42,11 @@ class tst_QNumeric: public QObject
private slots:
void fuzzyCompare_data();
void fuzzyCompare();
void qNanInf();
void rawNaN_data();
void rawNaN();
void generalNaN_data();
void generalNaN();
void infinity();
void classifyfp();
void floatDistance_data();
void floatDistance();
@ -53,6 +57,8 @@ private slots:
void mulOverflow_data();
void mulOverflow();
void signedOverflow();
private:
void checkNaN(double nan);
};
void tst_QNumeric::fuzzyCompare_data()
@ -92,44 +98,89 @@ 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));
QCOMPARE(nan, nan);
QCOMPARE(nan, -nan);
Q_STATIC_ASSERT(sizeof(double) == 8);
#ifdef Q_LITTLE_ENDIAN
const uchar bytes[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f };
#else
const uchar bytes[] = { 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
#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);
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
}
double inf = qInf();
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();
}
void tst_QNumeric::rawNaN()
{
QFETCH(double, nan);
checkNaN(nan);
}
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[] = { uchar(least), 0, 0, 0, 0, 0, uchar(next), uchar(most) };
#else
const uchar bytes[] = { uchar(most), uchar(next), 0, 0, 0, 0, 0, uchar(least) };
#endif
memcpy(&nan, bytes, 8);
checkNaN(nan);
}
void tst_QNumeric::infinity()
{
const double inf = qInf();
QVERIFY(inf > 0);
QVERIFY(-inf < 0);
QVERIFY(qIsInf(inf));
@ -138,16 +189,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);