Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java signed zero and boxing

Lately I've written a project in Java and noticed a very strange feature with double/Double implementation. The double type in Java has two 0's, i.e. 0.0 and -0.0 (signed zero's). The strange thing is that:

0.0 == -0.0 

evaluates to true, but:

new Double(0.0).equals(new Double(-0.0)) 

evaluates to false. Does anyone know the reason behind this?

like image 461
uhz Avatar asked Feb 08 '13 11:02

uhz


2 Answers

It is all explained in the javadoc:

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.


Now you might ask why 0.0 == -0.0 is true. In fact they are not strictly identical. For example:

Double.doubleToRawLongBits(0.0) == Double.doubleToRawLongBits(-0.0); //false 

is false. However, the JLS requires ("in accordance with the rules of the IEEE 754 standard") that:

Positive zero and negative zero are considered equal.

hence 0.0 == -0.0 is true.

like image 190
assylias Avatar answered Oct 03 '22 22:10

assylias


It important to undertand the use of signed zero in the Double class. (Loads of experienced Java programmers don't).

The short answer is that (by definition) "-0.0 is less than 0.0" in all the methods provided by the Double class (that is, equals(), compare(), compareTo(), etc)

Double allows all floating point numbers to be "totally ordered on a number line". Primitives behave the way a user will think of things (a real world definition) ... 0d = -0d

The following snippets illustrate the behaviour ...

final double d1 = 0d, d2 = -0d;  System.out.println(d1 == d2); //prints ... true System.out.println(d1 < d2);  //prints ... false System.out.println(d2 < d1);  //prints ... false System.out.println(Double.compare(d1, d2)); //prints ... 1 System.out.println(Double.compare(d2, d1)); //prints ... -1 

There are other posts that are relevant and nicely explain the background ...

1: Why do floating-point numbers have signed zeros?

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

And a word of caution ...

If you don't know that, in the Double class, "-0.0 is less than 0.0", you may get caught out when using methods like equals() and compare() and compareTo() from Double in logic tests. For example, look at ...

final double d3 = -0d; // try this code with d3 = 0d; for comparison  if (d3 < 0d) {          System.out.println("Pay 1 million pounds penalty"); } else {                System.out.println("Good things happen"); // this line prints }   if (Double.compare(d3, 0d) < 0) { //use Double.compare(d3, -0d) to match the above behaviour     System.out.println("Pay 1 million pounds penalty"); // this line prints } else {                                   System.out.println("Good things happen");  } 

and for equals you might try ... new Double(d3).equals(0d) || new Double(d3).equals(-0d)

like image 22
K John Smith Avatar answered Oct 03 '22 21:10

K John Smith