如何进行浮点数比较?

126

我正在编写一些代码,其中有类似以下内容的部分:

double a = SomeCalculation1();
double b = SomeCalculation2();

if (a < b)
    DoSomething2();
else if (a > b)
    DoSomething3();

然后在其他地方,我可能需要进行相等性比较:

double a = SomeCalculation3();
double b = SomeCalculation4();

if (a == 0.0)
   DoSomethingUseful(1 / a);
if (b == 0.0)
   return 0; // or something else here

简而言之,我需要进行大量浮点数计算,并且需要进行各种条件比较。在此情况下,将其转换为整数运算是没有意义的。

我之前读到过关于浮点数比较不可靠的文章,因为可能出现这样的情况:

double a = 1.0 / 3.0;
double b = a + a + a;
if ((3 * a) != b)
    Console.WriteLine("Oh no!");

简言之,我想知道:如何可靠地比较浮点数(小于、大于、相等)?

我使用的数字范围大约从10E-14到10E6,因此我需要处理小数和大数。

我将此标记为语言无关,因为我想知道我可以在任何语言中实现这个功能。


使用浮点数时,无法可靠地完成此操作。计算机始终会存在一些数字,它们在现实中并不相等,但对于计算机来说却是相等的(例如1E + 100,1E + 100 + 1),而通常还会有一些计算结果,在现实中它们是相等的,但对于计算机来说却不相等(请参见nelhage回答中的评论之一)。您必须选择其中一个优先级较低的结果。 - toochin
另一方面,如果您只涉及有理数,可以基于整数实现一些有理数算术运算,然后当其中一个数字被约分为另一个数字时,这两个数字被视为相等。 - toochin
目前我正在进行一项模拟工作。我通常进行这些比较的地方与可变时间步长有关(用于解决某些ode)。有几种情况需要检查一个对象的给定时间步长是否等于、小于或大于另一个对象的时间步长。 - Mike Bailey
浮点数比较的最有效方法 - phuclv
13个回答

0
你对这个解决方案有什么看法?
#define TRUE 1
#define FALSE 0

bool float_compare (float a, float b) ;

bool float_compare (float a, float b) 
{
    if ( a > b)
        return FALSE;

    if ( b > a )
        return FALSE;
        
    return TRUE;
}

int main()
{
    bool res = FALSE;
    float X = 0.00001;
    float Y = 0.00001;
    
    res = float_compare (X, Y) ;
    
    if (res) {
        /* Do what you need to, if X and Y are equal */
        
    } else {
        /* Do what you need to, if X and Y are NOT equal */
        
    }

    return 0;
}

这个逻辑应该适用于任何数据类型,比如double / float / int /等等。
我有什么遗漏吗?

这个功能与执行a == b没有任何区别,所以是的,它缺少很多东西。 - undefined

-1

在编程中比较两个双精度浮点数是否相等/不相等的最佳方法是取它们差的绝对值并将其与足够小(根据您的上下文而定)的值进行比较。

double eps = 0.000000001; //for instance

double a = someCalc1();
double b = someCalc2();

double diff = Math.abs(a - b);
if (diff < eps) {
    //equal
}

-1

你需要考虑到截断误差是相对的。如果两个数字的差大约等于它们的最后一位单位(ulp),那么它们就大致相等。

然而,如果你进行浮点数计算,每次操作都会增加误差潜力(特别是减法要小心!),因此你的误差容限需要相应增加。


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