比较Java中的相等的双重值.

chr*_*zie 9 java double double-precision

我想从那些double在Java中使用原始相等经验的人那里得到一些建议.使用d1 == d2两个双打d1并且d2由于可能的舍入误差而不够.

我的问题是:

  1. Java是否Double.compare(d1,d2) == 0在某种程度上处理舍入错误?如1.7文档中所述,0如果d1在数值上等于,则返回值d2.是否有人确定它们在数值上是什么意思?

  2. 对某些delta值使用相对误差计算,是否会推荐使用delta的通用(非特定于应用程序)值?请参阅下面的示例.

下面是考虑相对误差来检查相等性的通用函数.delta您建议从简单的操作+, - ,/,*操作中捕获大多数舍入错误的价值是多少?

public static boolean isEqual(double d1, double d2) {
    return d1 == d2 || isRelativelyEqual(d1,d2);
}

private static boolean isRelativelyEqual(double d1, double d2) {
    return delta > Math.abs(d1- d2) / Math.max(Math.abs(d1), Math.abs(d2));
}
Run Code Online (Sandbox Code Playgroud)

Hen*_*nry 6

您可以尝试使用10 -15数量级的增量值,但是您会注意到一些计算会产生较大的舍入误差。此外,您进行的操作越多,累积的舍入误差就越大。

一种特别糟糕的情况是,如果减去两个几乎相等的数字,例如1.0000000001-1.0并将结果与​​0.0000000001进行比较

因此,几乎没有希望找到适用于所有情况的通用方法。您始终必须计算出在特定应用中可以期望的精度,然后如果结果比该精度更接近,则认为结果相等。

例如输出

public class Main {

    public static double delta(double d1, double d2) {
        return Math.abs(d1- d2) / Math.max(Math.abs(d1), Math.abs(d2));
    }

    public static void main(String[] args) {
        System.out.println(delta(0.1*0.1, 0.01));
        System.out.println(delta(1.0000000001 - 1.0, 0.0000000001));
    }

}
Run Code Online (Sandbox Code Playgroud)

1.7347234759768068E-16
8.274036411668976E-8
Run Code Online (Sandbox Code Playgroud)

间隔算术可用于跟踪累积的舍入误差。但是实际上,错误间隔过于悲观,因为有时舍入错误也会相互抵消。