在 Java 中比较双精度值的相等性。
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25160375/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Comparing double values for equality in Java.
提问by chr0mzie
I would like some advice from people who have more experience working with primitive double
equality in Java. Using d1 == d2
for two doubles d1
and d2
is not sufficient due to possible rounding errors.
我想从那些double
在 Java 中处理原始平等方面有更多经验的人那里得到一些建议。使用d1 == d2
了两个双打d1
和d2
不充分,由于可能的舍入误差。
My questions are:
我的问题是:
Is Java's
Double.compare(d1,d2) == 0
handling rounding errors to some degree? As explained in the 1.7 documentationit returns value0
ifd1
is numerically equal tod2
. Is anyone certain what exactly they mean by numerically equal?Using relative error calculation against some delta value, is there a generic (not application specific) value of delta you would recommend? Please see example below.
Java 是否
Double.compare(d1,d2) == 0
在某种程度上处理舍入错误?如1.7 文档中所述,0
如果d1
数值等于 ,则返回值d2
。有人确定它们在数字上相等的确切含义吗?使用针对某些 delta 值的相对误差计算,是否有您会推荐的通用(非特定于应用程序)delta 值?请看下面的例子。
Below is a generic function for checking equality considering relative error. What value of delta
would you recommend to capture the majority of rounding errors from simple operations +,-,/,* operations?
下面是考虑相对误差的用于检查相等性的通用函数。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));
}
采纳答案by Henry
You could experiment with delta values in the order of 10-15but you will notice that some calculations give a larger rounding error. Furthermore, the more operations you make the larger will be the accumulated rounding error.
您可以尝试使用 10 -15数量级的 delta 值,但您会注意到某些计算会产生更大的舍入误差。此外,您进行的操作越多,累积的舍入误差就越大。
One particularly bad case is if you subtract two almost equal numbers, for example 1.0000000001 - 1.0 and compare the result to 0.0000000001
一种特别糟糕的情况是,如果您减去两个几乎相等的数字,例如 1.0000000001 - 1.0 并将结果与 0.0000000001 进行比较
So there is little hope to find a generic method that would be applicable in all situations. You always have to calculate the accuracy you can expect in a certain application and then consider results equal if they are closer than this accuracy.
因此,几乎没有希望找到适用于所有情况的通用方法。您始终必须计算在特定应用程序中可以预期的准确度,然后如果它们比此准确度更接近,则将结果视为相等。
For example the output of
例如输出
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));
}
}
is
是
1.7347234759768068E-16
8.274036411668976E-8
Interval arithmeticcan be used to keep track of the accumulated rounding errors. However in practise the error intervals come out too pessimistic, because sometimes rounding errors also cancel each other.
间隔算术可用于跟踪累积的舍入误差。然而在实践中,误差区间过于悲观,因为有时舍入误差也会相互抵消。
回答by Rahul Tripathi
From the javadoc for compareTo
来自 compareTo 的 javadoc
- Double.NaN is considered by this method to be equal to itself and greater than all other double values (including Double.POSITIVE_INFINITY).
- 0.0d is considered by this method to be greater than -0.0d.
- 此方法认为 Double.NaN 等于自身并大于所有其他双精度值(包括 Double.POSITIVE_INFINITY)。
- 此方法认为 0.0d 大于 -0.0d。
You may find this articlevery helpful
您可能会发现这篇文章非常有帮助
If you want you can check like
如果你愿意,你可以检查
double epsilon = 0.0000001;
if ( d <= ( 0 - epsilon ) ) { .. }
else if ( d >= ( 0 + epsilon ) ) { .. }
else { /* d "equals" zero */ }
回答by Hot Licks
You could try something like this (not tested):
你可以尝试这样的事情(未测试):
public static int sortaClose(double d1, double d2, int bits) {
long bitMask = 0xFFFFFFFFFFFFFFFFL << bits;
long thisBits = Double.doubleToLongBits(d1) & bitMask;
long anotherBits = Double.doubleToLongBits(d2) & bitMask;
if (thisBits < anotherBits) return -1;
if (thisBits > anotherBits) return 1;
return 0;
}
"bits" would typically be from 1 to 4 or so, depending on how precise you wanted the cutoff.
“位”通常为 1 到 4 左右,具体取决于您希望截止的精确程度。
A refinement would be to add 1 to the position of the first bit to be zeroed before masking (for "rounding"), but then you have to worry about ripple all the way up past the most significant bit.
一种改进是在屏蔽之前将要归零的第一位的位置加 1(用于“舍入”),但是您必须担心一直超过最高有效位的波纹。