如何比较双精度浮点数并限制小数位数?

4

Qt 提供了 qFuzzyCompare 函数来比较 double 类型的数值,例如:

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

如果我要比较以下值387.109287103387.109287101qFuzzyCompare将返回false,这是有道理的,因为这些值不相等。 如何限制小数位数以比较两个双精度值? 例如,将小数位数限制为6,两个值(387.109287387.109287)将相等。
我已经实现了以下函数来完成此操作:
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);
}

但我不确定这是否是最好的方法,因为它会将值转换为 QString,然后再转换回 double


以下是完整示例:

#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;
}

注意:我正在使用Qt 5.3。


乘以10^precision,转换为int,然后再进行比较? - Fureeish
@cse 我认为这不是重复的。另一个问题与限制小数位无关。 - KelvinS
@KelvinS 在提供的答案中提到:Qt 内部使用 (qAbs(p1 - p2) * 1000000000000. <= qMin(qAbs(p1), qAbs(p2)));。因此,你的查询应该已经解决了。 - cse
2个回答

16

比较两个浮点数通常采用将它们相减,取结果的绝对值,并将其与一个“epsilon”值进行比较的方式。

在您的情况下,可以像这样做:

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

例如,对于精度为6,则std::pow(10, -precision)应等于0.000001(这是epsilon),如果两个值之间的差小于该值,则认为它们相等。


2
@rafix07 通常的算术转换会导致整数提升,因此结果将是一个 int - Some programmer dude
1
这将返回true(相等),例如:5.12和5.11相比较到2个小数位。有关详细信息,请参见下面的我的答案。 - denim

2
接受的答案将返回true(相等)例如:5.12和5.11与2个小数位进行比较:
double value1 = 5.12;
double value2 = 5.11;
bool result = compare2(value1, value2, 2); // result will be true

这是因为5.12 - 5.11等于0.01,但在浮点数中表示为0.009999999999999787。相反,我使用以下方法解决此问题,通过进行整数比较来解决:
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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接