AMA
AMA

Reputation: 4214

QCOMPARE of two floating-point infinity-values

QCOMPARE(
    std::numeric_limits<double>::infinity(),
    std::numeric_limits<double>::infinity());

fails with:

Compared doubles are not the same (fuzzy compare)
       Actual   (std::numeric_limits<double>::infinity()): inf
       Expected (std::numeric_limits<double>::infinity()): inf
       Loc: [...]

Question

Why does this fail? Is there a good work-around (other than using QVERIFY instead)?

UPDATE:

I mean a work-around from the perspective of a test-writer. It is desirable to provide a proper diagnostic with the actual value which is not infinity. Instead of

QCOMPARE(val, std::numeric_limits<double>::infinity());

one could

QVERIFY(val == std::numeric_limits<double>::infinity()))

but the value of val is not shown in the generated diagnostic message if the check fails. Looks like a major oversight from developers. So do I have to roll-out my own macro with exact comparison similar to QCOMPARE? Any recommendations here?

Also, it is clear that qFuzzyCompare does not support some corner-cases. But I hoped for a more in-depth explanation of why this is the case.

Upvotes: 0

Views: 3525

Answers (4)

Jay-Pi
Jay-Pi

Reputation: 428

Based on the approach by @thomas-klier, the following macro works for me:

#define COMPARE_DBL(actual, expected, epsilon) \
do {\
    if (!QTest::compare_helper( ((qAbs(actual - expected) <= epsilon) || (actual == expected)), \
        QString{"Compared values are not the same in respect to epsilon %1"} \
             .arg(epsilon).toLocal8Bit().constData(), \
        QTest::toString(actual), \
        QTest::toString(expected), \
        #actual, #expected, __FILE__, __LINE__)) \
        return;\
} while (false)

Upvotes: 1

Thomas Klier
Thomas Klier

Reputation: 469

As there is still no working example, I post my own macro here:

#include <qtestcase.h>

#define COMPARE_DBL(actual, expected, epsilon) \
do {\
    if (!QTest::compare_helper((qAbs(actual - expected) <= epsilon), \
                               QString{"Compared values are not the same in respect to epsilon %1"} \
                                    .arg(epsilon).toLocal8Bit().constData(), \
                               QTest::toString(actual), \
                               QTest::toString(expected), \
                               #actual, #expected, __FILE__, __LINE__)) \
        return;\
} while (false)

It prints out an error message formatted by Qt and correctly interrupts the test case.

Upvotes: 3

AMA
AMA

Reputation: 4214

I ended up writing a custom marco. It mimics QCOMPARE output and does not stick out.

Here it is (feel free to re-use):

inline void isEqualsExactly(
    const double actual,
    const double expected,
    const std::string& actualName,
    const std::string& expectedName)
{
    if(expected == actual)
        return;
    std::stringstream warn;
    const size_t w = std::max(actualName.length(), expectedName.length());
    warn << "Compared values are not the same" << std::endl;
    warn << "   Actual   " << std::setw(w) << std::setfill(' ') << actualName;
    warn << ": " << std::to_string(actual) << std::endl;
    warn << "   Expected " << std::setw(w) << std::setfill(' ') << expectedName;
    warn << ": " << std::to_string(expected);
    QFAIL(warn.str().c_str());
}

#define QCOMPARE_EXACT(actual, expected) \
    isEqualsExactly(actual, expected, #actual, #expected);

Usage:

const double val = 0;
const double infinity = std::numeric_limits<double>::infinity();
QCOMPARE_EXACT(val, infinity);

Output:

FAIL!  : TestName Compared values are not the same
   Actual        val: 0.000000
   Expected infinity: inf  
   Loc: [link to location in file]

P.S. I agree, this should be a feature request. The situation is ridiculous. If I will make one, I will update the post.

Upvotes: 0

Pavan Chandaka
Pavan Chandaka

Reputation: 12821

QCOMPARE in the case of comparing floats and doubles, qFuzzyCompare() is used. (http://doc.qt.io/qt-5/qtest.html#QCOMPARE)

Based on (http://doc.qt.io/qt-5/qtglobal.html#qFuzzyCompare), Qt documentation it self says that comparing infinity will not work. - "Note that comparing values where either p1 or p2 is 0.0 will not work, nor does comparing values where one of the values is NaN or infinity".

My guess, why infinity can not be compared is, there is no specific value for infinity,I mean "infinity-1" is also infinity. Then obviously comparison is a question here.

Workaround:

If you want to compare infinity, Then use below function and compare the return Boolean values.

bool qIsInf(double d)

http://doc.qt.io/qt-5/qtglobal.html#qIsInf

Upvotes: 3

Related Questions