-1

I have two double values (primitive types and NOT objects!) and when I let Eclipse generate equals/hashCode for these double values, then it will override it like that:

@Override
public boolean equals(Object obj) {
...
return Double.doubleToLongBits(mydouble) == Double.doubleToLongBits(obj.mydouble) && ..;

}

So it uses doubleToLongBits to compare for equality. However, when using doubleToLongBits the comparision of 0!=-0 returns false. Why is this wanted within equals-method?

My question: Why Eclipse does not simply use the

 @Override
 public boolean equals(Object obj) {
 ..
 return mydouble == obj.mydouble && ..;
 }

to compare for equality? Would this be wrong?

Problem is specific for primitive types and why one should favor doubleToLongBits with primitive types instead of simply use, e.g. 0.1 == 0.1.

nimo23
  • 5,170
  • 10
  • 46
  • 75
  • If "mydouble" is an object (e.g. "Double") instead of a primitive ("double") ... it would indeed be wrong. Q: Did you expect something different from 0.0 != -0.0? – paulsm4 Oct 03 '19 at 20:00
  • @paulsm4 no, my double is a primitive type. – nimo23 Oct 03 '19 at 20:01
  • 3
    I suggest you learn more about floating point numbers. They are inherently inexact approximations to the number you are trying to represent. This is especially a problem if the double value is a result of some calculations. See https://stackoverflow.com/questions/588004/is-floating-point-math-broken for a discussion of how that is a problem. – Code-Apprentice Oct 03 '19 at 20:02
  • @NathanHughes I know, however, `==` and `Double.compare(x,y)` exists for a reason.. – nimo23 Oct 03 '19 at 20:03
  • 5
    Consider also that with plain `==`, an object that contains a NaN as value for some field would never be equal to anything else, even itself. If you put it into a collection, the collection will then lie about it and claim it doesn't contain that thing. – harold Oct 03 '19 at 20:04
  • @harold so `Double.NaN != Double.NaN`..good point.. – nimo23 Oct 03 '19 at 20:11
  • @harold: I think you should post that as an answer. – ruakh Oct 03 '19 at 20:24
  • Déjà vu: https://stackoverflow.com/q/58166602/85421 ? – user85421 Oct 03 '19 at 20:25
  • @CarlosHeuberger yes, but in this case a little different because I use raw primitive types double instead of `Double` and dont see a sense in using `Double.doubleToLongBits` for primitive types. For wrapper types, using `doubleToLongBits` makes sense, but for primitive types??? – nimo23 Oct 03 '19 at 20:27
  • "Version1: `boolean isEqual(double a, double b){ return Double.doubleToLongBits(a) ==` ..." is that not using primitives? – user85421 Oct 03 '19 at 20:29
  • @CarlosHeuberger yes, and does this make sense? I dont think so. This method only makes sense if it s called `boolean isEqual(Double a, Double b){ return Double.doubleToLongBits(a) ==` – nimo23 Oct 03 '19 at 20:30
  • Why can it not be simply: `boolean isEqual(double a, double b){ return a ==b;}` That would be the correct way, I think. Or? – nimo23 Oct 03 '19 at 20:32
  • "little different because I use raw primitive types double instead of Double" but you just confirmed that it is also about primitive double, like here. Why you need `isEqual` if it is the same as `==` (correct way depends on context) – user85421 Oct 03 '19 at 20:38
  • @CarlosHeuberger good point, I let eclipse generate my `equals/hashCode` and wanted to delete `doubleToLongBits` and use simply `==` instead because with this `0==-0`which is what I want..dont see any sense in using `doubleToLongBits` with primitive types..do you? – nimo23 Oct 03 '19 at 20:41

2 Answers2

1

It does it this way, because it follows Double.compare() implementation - so its consistent with what Java provides by default:

public static int compare(double d1, double d2) { //Java 12 implementation
    if (d1 < d2)
        return -1;           // Neither val is NaN, thisVal is smaller
    if (d1 > d2)
        return 1;            // Neither val is NaN, thisVal is larger

    // Cannot use doubleToRawLongBits because of possibility of NaNs.
    long thisBits    = Double.doubleToLongBits(d1);
    long anotherBits = Double.doubleToLongBits(d2);

    return (thisBits == anotherBits ?  0 : // Values are equal
            (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
             1));                          // (0.0, -0.0) or (NaN, !NaN)
}

Edit: Also equals for same class

public boolean equals(Object obj) {
    return (obj instanceof Double)
           && (doubleToLongBits(((Double)obj).value) ==
                  doubleToLongBits(value));
}
Worthless
  • 531
  • 3
  • 7
  • I know that Double.compare can use doubleToLongBits under the hood. That is not the question. The question is: Why should I use that instead of raw "==" – nimo23 Oct 03 '19 at 20:12
1

To answer "Why does Eclipse use doubleToLongBits"?

This is code generation functionality. Eclipse doesn't know the context. It is just trying to grunt out something that is mostly ok. If it generates something like this.d == that.d it will set off all kinds of static analysis tools that will flag the line as comparing two doubles (because they have rules like this one). Instead it compares longs and the static analysis tools are happy, because they're stupid (useful for a lot of things, but easily fooled).

If you are using doubles then there is some tolerance within which differentiating between two values is not useful. Neither one of these alternatives really helps you more than the other with respect to this. It's just one trips the static analysis tools' triggers more than the other.

Typically when you create an equals method it is for some domain object. The equals and hashcode methods don't necessarily take all the fields on the object into account, a lot of the time they use a subset called the business key, that identifies the object uniquely. It could be here that you don't need to include this field in the equals or hashCode methods at all. Again, code generators have no context to go on, and are going to provide a way to include all fields whether it makes sense or not.

Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
  • That helped me, thanks! So it will be **NOT** wrong to compare raw double values with `this.d == that.d` instead of `doubleToLongBits`. Because with this, `0==-0` will return true, which is what I want. However, as you said about the `business key`..thats a good point. Thanks! – nimo23 Oct 03 '19 at 20:51