Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare double values limiting the decimal places?

Tags:

c++

qt

Qt provides the qFuzzyCompare function to compare doubles, for example:

bool compare(double value1, double value2)
{
    return qFuzzyCompare(value1, value2);
}

If I try to compare the following values 387.109287103 and 387.109287101, qFuzzyCompare will return false, what makes sense, since the values are not equal.

How can I limit the decimal places to compare two double values?

For example, limiting the decimal places to 6 the two values (387.109287 and 387.109287) will be equal.

I have implemented the following function to do that:

bool compare(double value1, double value2, quint8 precision)
{
    value1 = QString::number(value1, 'f', precision).toDouble();
    value2 = QString::number(value2, 'f', precision).toDouble();

    return qFuzzyCompare(value1, value2);
}

But I'm not sure if it is the best way to do that, since it convert the values to QString and then convert back to double.


Here is the full example:

#include <QDebug>
#include <QtGlobal>

bool compare(double value1, double value2)
{
    return qFuzzyCompare(value1, value2);
}

bool compare(double value1, double value2, quint8 precision)
{
    value1 = QString::number(value1, 'f', precision).toDouble();
    value2 = QString::number(value2, 'f', precision).toDouble();

    return qFuzzyCompare(value1, value2);
}

int main()
{
    qDebug() << compare(387.109287103, 387.109287101);    // False
    qDebug() << compare(387.109287103, 387.109287101, 6); // True
    return 0;
}

Note: I'm using Qt 5.3.

like image 749
KelvinS Avatar asked Sep 05 '25 03:09

KelvinS


2 Answers

The usual way to compare two floating point values is to subtract them from each other, get the absolute value of the result, and compare it to an epsilon value.

In your case it could be something like

bool compare(double value1, double value2, quint8 precision)
{
    return std::abs(value1 - value2) < std::pow(10, -precision);
}

For a precision of e.g. 6 then std::pow(10, -precision) should equal 0.000001 (this is the epsilon), and if the difference between the two values is smaller than that they are considered equal.

like image 196
Some programmer dude Avatar answered Sep 07 '25 20:09

Some programmer dude


The accepted answer will return true (is equal) for e.g.: 5.12 and 5.11 compared to 2 decimal places:

double value1 = 5.12;
double value2 = 5.11;
bool result = compare2(value1, value2, 2); // result will be true

This is because 5.12 - 5.11 equals to 0.01 but will be represented as 0.009999999999999787 in the floating point number.

I am using the following approach instead that works around this problem by doing an integer comparison:

bool compare(const double value1, const double value2, const int precision)
{
    int64_t magnitude = static_cast<int64_t>(std::pow(10, precision));
    int64_t intValue1 = static_cast<int64_t>(value1 * magnitude);
    int64_t intValue2 = static_cast<int64_t>(value2 * magnitude);
    return intValue1 == intValue2;
}
like image 23
denim Avatar answered Sep 07 '25 20:09

denim