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

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

问题描述

我目前正在编写一些代码,其中包含以下内容:

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.

推荐答案

除非您工作在浮点/双精度限制的边缘,否则比较更大/更小并不是真正的问题.

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.

无论如何,可能没有适合所有应用程序的解决方案.理想情况下,您应该使用涵盖实际用例的测试套件来开发/调整自己的测试套件.

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天全站免登陆