我应该如何做浮点比较? [英] How should I do floating point comparison?

查看:104
本文介绍了我应该如何做浮点比较?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在写一些代码,其中我有以下的行:

I'm currently writing some code where I have something along the lines of:

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

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

然后在其他地方,我可能需要做平等:

And then in other places I may need to do equality:

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

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

简而言之,我有很多浮点运算,做各种条件的比较。我不能将它转换为整数数学,因为这样的事情在这种情况下是无意义的。

In short, I have lots of floating point math going on and I need to do various comparisons for conditions. I can't convert it to integer math because such a thing is meaningless in this context.

我之前读过浮点数比较可能是不可靠的,因为你可以有这样的事情:

I've read before that floating point comparisons can be unreliable, since you can have things like this going on:

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

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

我使用的数字范围大约是10E-14到10E6,所以我需要工作

The number range I am using is roughly from 10E-14 to 10E6, so I do need to work with small numbers as well as large.

我已将此标记为语言不可知,因为我对我无论使用什么语言都能做到这一点感兴趣。

I've tagged this as language agnostic because I'm interested in how I can accomplish this no matter what language I'm using.

推荐答案

比较更大/更小并不是一个问题,除非你在float / double精度限制。

Comparing for greater/smaller is not really a problem unless you're working right at the edge of the float/double precision limit.

对于模糊等于比较,这个(Java代码,应该很容易适应)是我想出的浮点指南经过大量的工作和考虑到许多批评:

For a "fuzzy equals" comparison, this (Java code, should be easy to adapt) is what I came up with for The Floating-Point Guide after a lot of work and taking into account lots of criticism:

public static boolean nearlyEqual(float a, float b, float epsilon) {
    final float absA = Math.abs(a);
    final float absB = Math.abs(b);
    final float diff = Math.abs(a - b);

    if (a == b) { // shortcut, handles infinities
        return true;
    } else if (a == 0 || b == 0 || diff < Float.MIN_NORMAL) {
        // a or b is zero or both are extremely close to it
        // relative error is less meaningful here
        return diff < (epsilon * Float.MIN_NORMAL);
    } else { // use relative error
        return diff / (absA + absB) < epsilon;
    }
}

它附带一个测试套件。你应该立即解开没有的解决方案,因为它几乎可以肯定在一些边缘情况下失败,如一个值为0,两个非常小的值相反的零或无穷大。

It comes with a test suite. You should immediately dismiss any solution that doesn't, because it is virtually guaranteed to fail in some edge cases like having one value 0, two very small values opposite of zero, or infinities.

一个替代方法(详见上面的链接)是将浮点数的位模式转换为整数,并接受固定整数距离内的所有内容。

An alternative (see link above for more details) is to convert the floats' bit patterns to integer and accept everything within a fixed integer distance.

case,可能没有任何解决方案是完美的所有应用程序。理想情况下,您可以使用涵盖您实际使用案例的测试套件开发/调整自己。

In any case, there probably isn't any solution that is perfect for all applications. Ideally, you'd develop/adapt your own with a test suite covering your actual use cases.

这篇关于我应该如何做浮点比较?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆