How to write a proper hashcode method for double values with limited precision? [duplicate]

泄露秘密 提交于 2019-12-24 07:25:04

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!