Why is Java's Double.compare(double, double) implemented the way it is?

Solution 1:

The explanation is in the comments in the code. Java has double values for both 0.0 and -0.0, as well as "not a number" (NaN). You can't use simple == operator for these values. Take a peek into the doubleToLongBits() source and at the Javadoc for the Double.equals() method:

Note that in most cases, for two instances of class Double, d1 and d2, the value of d1.equals(d2) is true if and only if

d1.doubleValue() == d2.doubleValue()

also has the value true. However, there are two exceptions:

  • If d1 and d2 both represent Double.NaN, then the equals method returns true, even though Double.NaN == Double.NaN has the value false.
  • If d1 represents +0.0 while d2 represents -0.0, or vice versa, the equal test has the value false, even though +0.0 == -0.0 has the value true.

This definition allows hash tables to operate properly.

Solution 2:

@Shoover's answer is correct (read it!), but there is a bit more to it than this.

As the javadoc for Double::equals states:

"This definition allows hash tables to operate properly."

Suppose that the Java designers had decided to implement equals(...) and compare(...) with the same semantics as == on the wrapped double instances. This would mean that equals() would always return false for a wrapped NaN. Now consider what would happen if you tried to use a wrapped NaN in a Map or Collection.

List<Double> l = new ArrayList<Double>();
l.add(Double.NaN);
if (l.contains(Double.NaN)) {
    // this wont be executed.
}

Map<Object,String> m = new HashMap<Object,String>();
m.put(Double.NaN, "Hi mum");
if (m.get(Double.NaN) != null) {
    // this wont be executed.
}

Doesn't make a lot of sense does it!

Other anomalies would exist because -0.0 and +0.0 have different bit patterns but are equal according to ==.

So the Java designers decided (rightly IMO) on the more complicated (but more intuitive) definition for these Double methods that we have today.

Solution 3:

The merit is that it's the simplest code that fulfills the specification.

One common characteristic of rookie programmers is to overvalue reading source code and undervalue reading specifications. In this case, the spec:

http://java.sun.com/javase/6/docs/api/java/lang/Double.html#compareTo%28java.lang.Double%29

... makes the behavior and the reason for the behavior (consistency with equals()) perfectly clear.