如何为精度有限的双精度值编写适当的哈希码方法? [英] How to write a proper hashcode method for double values with limited precision?
问题描述
如果double成员在另一个对象的给定范围内,则认为类Foo
的对象相等.由于浮点运算,很容易引入这种错误.
An object of class Foo
is considered equal if the double members are within a given range of the other object. Such an error can easily be introduced due to floating point arithmetic.
方法isDoubleEquals
和doubleArrayEquals
将处理equals部分,但合同规定,对于相等的对象,哈希码必须相同.
默认的double哈希码不会将close值映射到相同的值,因此,对于匹配double而言,获得相同哈希值的一种好方法是什么?
The method isDoubleEquals
and doubleArrayEquals
will take care of the equals part but the contract states that the hashcode has to be identical for equal objects.
The default hashcode of doubles will not map close values to the same value, therefore what would be a good approach to get the same hash value for matching doubles?
public class Foo {
double[] values;
public Foo(double[] values) {
this.values = values;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
//TODO Arrays.hashCode will not work with the contract
result = prime * result + Arrays.hashCode(values);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Foo other = (Foo) obj;
if (!doubleArrayEquals(values, other.values,1e-10))
return false;
return true;
}
private boolean doubleArrayEquals(double[] arr, double[] arr2, double epsilon) {
if (arr== arr2)
return true;
if (arr == null || arr2 == null)
return false;
int length = arr.length;
if (arr2.length != length)
return false;
for(int i = 0; i < length; i++) {
if(!isDoubleEquals(arr[i],arr2[i],epsilon)) {
return false;
}
}
return true;
}
private boolean isDoubleEquals(double needle, double target, double epsilon) {
return Math.abs(needle - target) <= epsilon;
}
}
推荐答案
您不能正确编写处理近似相等的equals
和hashCode
方法.
You cannot properly write equals
and hashCode
methods which deal with approximate equality.
equals
的合同需要可传递性,而近似相等性不是可传递性.
The contract of equals
requires transitivity, and approximate equality is not transitive.
并不是说近似相等不是一件有用的事情:这不是Java的equals
(和hashCode
)方法的用途,因此您应该定义自己的方法-例如isApproximatelyEqualTo
-支持它,而不会重载众所周知的Java方法.
That's not to say that approximate equality is not a useful thing: it's just not what Java's equals
(and hashCode
) methods are for, and therefore you should define your own method - say, isApproximatelyEqualTo
- to support it, without overloading the well-known Java methods.
这篇关于如何为精度有限的双精度值编写适当的哈希码方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!