如何为精度有限的双精度值编写正确的哈希码方法?
How to write a proper hashcode method for double values with limited precision?
如果 double 成员在另一个对象的给定范围内,则 class Foo
的对象被认为是相等的。由于浮点运算,很容易引入这样的错误。
方法 isDoubleEquals
和 doubleArrayEquals
将处理相等部分,但合同规定哈希码对于相等对象必须相同。
双打的默认哈希码不会将接近的值映射到相同的值,因此获得相同哈希值以匹配双打的好方法是什么?
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
方法。
equals
的契约要求传递性,近似相等是不可传递的。
这并不是说近似相等没有用:它不是 Java 的 equals
(和 hashCode
)方法的用途,因此您应该定义你自己的方法 - 比如 isApproximatelyEqualTo
- 来支持它,而不重载众所周知的 Java 方法。
如果 double 成员在另一个对象的给定范围内,则 class Foo
的对象被认为是相等的。由于浮点运算,很容易引入这样的错误。
方法 isDoubleEquals
和 doubleArrayEquals
将处理相等部分,但合同规定哈希码对于相等对象必须相同。
双打的默认哈希码不会将接近的值映射到相同的值,因此获得相同哈希值以匹配双打的好方法是什么?
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
方法。
equals
的契约要求传递性,近似相等是不可传递的。
这并不是说近似相等没有用:它不是 Java 的 equals
(和 hashCode
)方法的用途,因此您应该定义你自己的方法 - 比如 isApproximatelyEqualTo
- 来支持它,而不重载众所周知的 Java 方法。