Understanding Double autoboxing
Asked Answered
I

5

5

Consider the following example:

public static void main(String[] args) {
    double x1 = 0.0, y1 = -0.0;
    Double a1 = x1, b1 = y1;
    System.out.println(x1 == y1);       //1, true
    System.out.println(a1.equals(b1));  //2, false

    double x2 = 0.0, y2 = 0.0;
    Double a2 = x2, b2 = y2;
    System.out.println(x2 == y2);       //3, true
    System.out.println(a2.equals(b2));  //4, true

    double x3 = 0.0/0.0, y3 = 0.0/0.0;
    Double a3 = x3, b3 = y3;
    System.out.println(x3 != y3);       //5, true
    System.out.println(!a3.equals(b3)); //6, false
}

I tried to understand the autoboxing for Double, but could not. Why does the //2 print false, but //4 prints true whereas both //1 and //3 prints true. Why are they autoboxed in a different way?

Consulting the following JLS 5.1.7 section I realized that it's not specicified:

If p is a value of type double, then:

  • If p is not NaN, boxing conversion converts p into a reference r of class and type Double, such that r.doubleValue() evaluates to p

  • Otherwise, boxing conversion converts p into a reference r of class and type Double such that r.isNaN() evaluates to true

So, are //2, //4 and //6 yeild in unspecified behavior and might end up in different results depending on the implementation?

Indicatory answered 17/3, 2016 at 5:21 Comment(1)
docs.oracle.com/javase/8/docs/api/java/lang/… has the answer to your exact question.Flabbergast
G
5

All JAVA numeric types are signed unless specified differently

So, 0.0 is represented in binary as 0000000........0000000

-0.0 is represented as 10000000........0000000

Now, from what I understand, when you use equals() , the comparison is done in a bit-by-bit fashion from the 2 memory locations, so it fails in your case.

FROM THE java.lang.Double package

Double.equals(Double) is implemented as follows

public boolean equals(Object obj) {
    return (obj instanceof Double)
           && (doubleToLongBits(((Double)obj).value) ==
                  doubleToLongBits(value));
}
Galyak answered 17/3, 2016 at 5:31 Comment(3)
True for bit-by-bit, except that NaN values are "collapsed to a single "canonical" NaN value". See javadoc of Double.equals(Object obj) and Double.doubleToLongBits(double value).Anabranch
Added the internal implementation of the Double.equals(Double) method from the Java source package.Galyak
@Saibot Floating point uses sign-and-magnitude, not 2's complement. -0.0 has a 1 for the sign bit, and all the remaining bits 0.Pyuria
P
6

The Double equals method is documented in the API documentation. The double == operation is documented in the Java Language Specification.

For most pairs of numbers they have the same result, but they are based on different conventions.

The double == is compatible with IEEE 754 arithmetic, in which a NaN is not equal to anything, not even itself, but 0.0 and -0.0 are equal.

Double is designed to have an equals method is compatible with its compareTo, reflecting a total order, and with its hashCode, so hash tables will work with Double keys. NaN is treated as equal to itself, and -0.0 is less than, rather than equal to, 0.0.

Pyuria answered 17/3, 2016 at 5:33 Comment(0)
G
5

All JAVA numeric types are signed unless specified differently

So, 0.0 is represented in binary as 0000000........0000000

-0.0 is represented as 10000000........0000000

Now, from what I understand, when you use equals() , the comparison is done in a bit-by-bit fashion from the 2 memory locations, so it fails in your case.

FROM THE java.lang.Double package

Double.equals(Double) is implemented as follows

public boolean equals(Object obj) {
    return (obj instanceof Double)
           && (doubleToLongBits(((Double)obj).value) ==
                  doubleToLongBits(value));
}
Galyak answered 17/3, 2016 at 5:31 Comment(3)
True for bit-by-bit, except that NaN values are "collapsed to a single "canonical" NaN value". See javadoc of Double.equals(Object obj) and Double.doubleToLongBits(double value).Anabranch
Added the internal implementation of the Double.equals(Double) method from the Java source package.Galyak
@Saibot Floating point uses sign-and-magnitude, not 2's complement. -0.0 has a 1 for the sign bit, and all the remaining bits 0.Pyuria
C
2

If you read the Javadoc for Double closely, you will notice that negative and positive zero are not equivalent, at least under comparison using equals():

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

Chilson answered 17/3, 2016 at 5:34 Comment(1)
can you please explain in detail, how does the +0.0==-0.0 become true?Thorp
C
2

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

Please refer: https://docs.oracle.com/javase/7/docs/api/java/lang/Double.html

Calliecalligraphy answered 17/3, 2016 at 5:34 Comment(0)
A
1

Javadoc of Double.equals(Object obj):

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.

Anabranch answered 17/3, 2016 at 5:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.