Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Meaning of Double.doubleToLongBits(x)

I am writing a class Vec2D, representing a 2 dimensional vector. I store x and y in doubles.

When asked to generate equals(Object obj and hashCode(), eclipse generated this:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    long temp;
    temp = Double.doubleToLongBits(x);
    result = prime * result + (int) (temp ^ (temp >>> 32));
    temp = Double.doubleToLongBits(y);
    result = prime * result + (int) (temp ^ (temp >>> 32));
    return result;
}
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Vec2D other = (Vec2D) obj;
    if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
        return false;
    if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
        return false;
    return true;
}

What is the significance of Double.doubleToLongBits(x) in this context? Can I not simply write x != other.x?

like image 909
Kyranstar Avatar asked May 02 '14 23:05

Kyranstar


People also ask

What is double doubleToLongBits?

lang. Double. doubleToLongBits() method of Java Double class is a built-in function in java that returns a representation of the specified floating-point value according to the IEEE 754 floating-point “double format” bit layout.

What is double Positive_infinity?

public static final double POSITIVE_INFINITY. A constant holding the positive infinity of type double . It is equal to the value returned by Double.

What does double mean in eclipse?

Double. It represents single-precision numbers. It represents double-precision numbers. Width is 32 bits and the range is 1.4e–045 to 3.4e+038.


2 Answers

Short answer: Eclipse uses Double.doubleToLongBits because that's what Double.equals does:

The result is true if and only if the argument is not null and is a Double object that represents a double that has the same value as the double represented by this object. For this purpose, two double values are considered to be the same if and only if the method doubleToLongBits(double) returns the identical long value when applied to each.

Long answer: the JLS specifies a few differences between Double.equals and ==. For one difference specified in JLS 4.2.3 and JLS 15.21.1:

Positive zero and negative zero compare equal; thus the result of the expression 0.0==-0.0 is true and the result of 0.0>-0.0 is false. But other operations can distinguish positive and negative zero; for example, 1.0/0.0 has the value positive infinity, while the value of 1.0/-0.0 is negative infinity.

Another regards NaN:

If either operand is NaN, then the result of == is false but the result of != is true.

Indeed, the test x!=x is true if and only if the value of x is NaN.

As you can see, it's possible for two double values to compare with == but actually correspond to different behavior when used in math and hash tables. Thus, when writing a generated equality method, Eclipse makes the assumption that two doubles are only equal if and only if all operations that can be done to them are identical, or (equivalently) if they were autoboxed and compared with their equals methods. This is particularly important if switching between double and Double—it would be particularly unexpected for equality properties to differ there.

Of course, you're free to drift from that assumption: Regardless of whether it's a good idea, you may assign special cases to any of the many possible NaN representations, in which case Double.doubleToRawLongBits() would be a better match for your equals and hashCode methods. By the same token, your use case might treat objects with +0.0 and -0.0 as equivalent and guarantee that NaN values are not possible, in which case a raw == comparison may work better for equals (but at which point emulating the same criteria for hashCode becomes difficult).

like image 157
Jeff Bowman Avatar answered Oct 16 '22 18:10

Jeff Bowman


Because == and != follow IEEE-754 semantics for doubles, Double.NaN != Double.NaN and 0.0 == -0.0. These behaviors may not be what you want, so Double.doubleToLongBits() converts the 64 bits of double data to 64 bits of long data so that operations like bit shifts and XOR work.

Honestly, though, I would say that the use of doubleToLongBits is a bug here, since if you care about exact equality you should be using Double.doubleToRawLongBits() (which does not perform any translations on the double data at all) instead.

like image 40
Daniel Pryden Avatar answered Oct 16 '22 17:10

Daniel Pryden