signed zero double equals (as in ==) but Double.compare(double,double) != 0

apete :

I've encountered something strange regarding comparing double zeros. Depending on how the double zero primitives are initiated the Double.compare(double,double) method may or may not think that they are "equal" (may or may not return 0).

Comparing the various zero double:s using == always reports them as equal. If they are equal in terms of ==, they must (should) be equal in terms of the the compare method. They are not!

Check out this sample program:

public class CompareZeros {

public static void main(final String[] args) {

    final double negDbl = -0.0;
    final double posInt = 0;
    final double posDbl = 0.0;
    final double negInt = -0;

    CompareZeros.compare("negDbl <-> posInt", negDbl, posInt);
    CompareZeros.compare("negDbl <-> posDbl", negDbl, posDbl);
    CompareZeros.compare("negDbl <-> negInt", negDbl, negInt);

    CompareZeros.compare("posInt <-> negDbl", posInt, negDbl);
    CompareZeros.compare("posInt <-> posDbl", posInt, posDbl);
    CompareZeros.compare("posInt <-> negInt", posInt, negInt);

    CompareZeros.compare("posDbl <-> negDbl", posDbl, negDbl);
    CompareZeros.compare("posDbl <-> posInt", posDbl, posInt);
    CompareZeros.compare("posDbl <-> negInt", posDbl, negInt);

    CompareZeros.compare("negInt <-> negDbl", negInt, negDbl);
    CompareZeros.compare("negInt <-> posInt", negInt, posInt);
    CompareZeros.compare("negInt <-> posDbl", negInt, posDbl);

}

static void compare(final String id, final double arg0, final double arg1) {

    System.out.print(id + ": ");

    if (arg0 == arg1) {
        if (Double.compare(arg0, arg1) == 0) {
            System.out.println("OK");
        } else {
            System.out.println("Strange, and must be wrong!");
        }
    } else {
        if (Double.compare(arg0, arg1) == 0) {
            System.out.println("Strange, but perhaps logically ok");
        } else {
            System.out.println("Consistent...");
        }
    }

}
}

It outputs this:

negDbl <-> posInt: Strange, and must be wrong!
negDbl <-> posDbl: Strange, and must be wrong!
negDbl <-> negInt: Strange, and must be wrong!
posInt <-> negDbl: Strange, and must be wrong!
posInt <-> posDbl: OK
posInt <-> negInt: OK
posDbl <-> negDbl: Strange, and must be wrong!
posDbl <-> posInt: OK
posDbl <-> negInt: OK
negInt <-> negDbl: Strange, and must be wrong!
negInt <-> posInt: OK
negInt <-> posDbl: OK
Hulk :

Double.compare is documented to be equivalent to

public static int compare(double d1, double d2)

Compares the two specified double values. The sign of the integer value returned is the same as that of the integer that would be returned by the call:

   new Double(d1).compareTo(new Double(d2))

And the contract of compareTo, as specified by the interface Comparable requires this method to impose a total order:

This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.

Therefore it cannot implement the comparison relations defined by IEEE 754 and implemented by the numeric comparison operators:

The result of a floating-point comparison, as determined by the specification of the IEEE 754 standard, is:

  • If either operand is NaN, then the result is false.

  • All values other than NaN are ordered, with negative infinity less than all finite values, and positive infinity greater than all finite values.

  • Positive zero and negative zero are considered equal.

...which is obviously not a total order.


A total order is one of the preconditions for stable sorting, and certainly a desirable trait in a comparable type.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=474871&siteId=1