简体   繁体   中英

How to compare double values limiting the decimal places?

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.

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 eg 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.

The accepted answer will return true (is equal) for eg: 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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM