Comparing double values for equality in Java.

前端 未结 3 1336
野的像风
野的像风 2020-12-03 11:51

I would like some advice from people who have more experience working with primitive double equality in Java. Using d1 == d2 for two doubles

相关标签:
3条回答
  • 2020-12-03 12:31

    You could experiment with delta values in the order of 10-15 but 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.

    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

    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 arithmetic can 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.

    0 讨论(0)
  • 2020-12-03 12:31

    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.

    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.

    0 讨论(0)
  • 2020-12-03 12:41

    From the javadoc for compareTo

    • 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.

    You may find this article very 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 */ }
    
    0 讨论(0)
提交回复
热议问题