问题
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.
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;
}
}
回答1:
You cannot properly write equals
and hashCode
methods which deal with approximate equality.
The contract of equals
requires transitivity, and approximate equality is not transitive.
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.
来源:https://stackoverflow.com/questions/53812230/how-to-write-a-proper-hashcode-method-for-double-values-with-limited-precision