How to compare that sequence of doubles are all “approximately equal” in Java?

前端 未结 7 2104
感动是毒
感动是毒 2021-02-07 02:22

I have a method in java that returns a double number and I want to compare every double number that is returned every time I call the method(say 5 times), so that I can conclude

相关标签:
7条回答
  • 2021-02-07 02:32

    You could use Guava and DoubleMath#fuzzyEquals method (since version 13.0):

    public static boolean fuzzyEquals(double a, double b, double tolerance)
    

    Returns true if a and b are within tolerance of each other. Technically speaking, this is equivalent to Math.abs(a - b) <= tolerance || Double.valueOf(a).equals(Double.valueOf(b)).

    Notable special cases include:

    Link to docs: https://google.github.io/guava/releases/17.0/api/docs/com/google/common/math/DoubleMath.html

    0 讨论(0)
  • 2021-02-07 02:45

    The Apache commons-math library provides the nice Precision class (see API Docs), that can compare doubles in different ways:

    Precision.equals(a, b, 0.1); // Tell if |a-b| <= 0.1
    Precision.equals(a, b, 10); // Tell if a and b are less than 10 Ulps apart
    Precision.equalsWithRelativeTolerance(a, b, 0.05); // Tell if a and b are less than 5% apart
    
    0 讨论(0)
  • 2021-02-07 02:47

    You must first decide what "almost the same" means. For example, there's a method in java.lang.Math called ulp() which, given a double, returns the distance between that double and the next; i.e., the smallest possible difference between that number and any other. You might simply compare the difference between the two doubles and the result of calling that method.

    On the other hand, maybe you want two numbers to just be within 1% of eachother. In that case, do the same computation, but use the first number multiplied by 0.01 instead of ulp() as the largest acceptable distance.

    0 讨论(0)
  • 2021-02-07 02:48
    public static boolean almostEqual(double a, double b, double eps){
        return Math.abs(a-b)<eps;
    }
    

    Where eps is measure of equality.

    0 讨论(0)
  • 2021-02-07 02:49

    It depends on what you mean by similar. If you want to compare two numbers within an absolute error e.g. 1e-6 you can use epsilon. If you want to compare two double regardless of scale. e.g. 1.1e-20 and 1.3e-20 are not similar but 1.1e20 and 1.1e20+1e5 are you can compare the raw value.

    public static void main(String... args) throws IOException {
        test(1.1e-20, 1.3e-20);
        test(1.1e20, 1.1e20 + 1e5);
    }
    
    private static void test(double a, double b) {
        System.out.println(a + " and " + b + ", similar= " + similarUnscaled(a, b, 10));
    }
    
    public static boolean similarUnscaled(double a, double b, long representationDifference) {
        long a2 = Double.doubleToRawLongBits(a);
        long b2 = Double.doubleToRawLongBits(b);
        // avoid overflow in a2 - b2
        return ((a2 >= 0) == (b2 >= 0)) &&
                Math.abs(a2 - b2) <= representationDifference;
    }
    

    prints

    1.1E-20 and 1.3E-20, similar= false
    1.1E20 and 1.100000000000001E20, similar= true
    
    0 讨论(0)
  • 2021-02-07 02:52

    Approximate equality is defined in terms of the absolute difference: if an absolute difference does not exceed a certain, presumably small, number, then you can say that the values you are comparing are "close enough".

    double diff = Math.abs(actual - expected);
    if (diff < 1E-7) {
        // Numbers are close enough
    }
    

    You must be very careful to not confuse "close enough" end "equals", because the two are fundamentally different: equality is transitive (i.e. a==b and b==c together imply that a==c), while "close enough" is not transitive.

    0 讨论(0)
提交回复
热议问题