2

I came across some old legacy code as the below:

s1 = Double.toString(dbVal1);
s2 = Double.toString(dbVal2);
if (s1.compareTo(s2)!=0)
{
    return false;
}
return true;

where dbVal1 and dbVal2 are both double values.

I found this while profiling, and the toString method calls take a fair amount of CPU time. Is there any reason I couldn't replace this with 1 or 2? If so, is there any difference / which one is better?

1.

return dbVal1 == dbVal2;

2.

return Double.compare(dbVal1,dbVal2) == 0;
Melika Barzegaran
  • 429
  • 2
  • 9
  • 25
Andrew Wirtz
  • 23
  • 1
  • 3
  • It seems that you can...Is there any reason for that String cast?? – DGomez Mar 10 '15 at 19:34
  • Maybe, for some reason, they wanted lexicographic order on those `double`s? – kooker Mar 10 '15 at 19:39
  • That's what I want to remove, it's causing a lot of slow down, but didn't know if it was necessary for some reason I can't think of. – Andrew Wirtz Mar 10 '15 at 19:40
  • @kooker Lexicographic order is only relevant with `<` / `>` resp. `compare() > 0`. Here we just check for `==` resp. `== 0`, so the order is not relevant. – glglgl Mar 10 '15 at 19:43
  • I guess original programmer was trying to avoid rounding errors? Check out this answer: http://stackoverflow.com/questions/8081827/how-to-compare-two-double-values-in-java – zmf Mar 10 '15 at 19:44

4 Answers4

1

Normally, double values are compared in a way that their absolute difference lies within a certain range.

This is because of the way how doubles are internally represented and because of the rounding errors which may arise, depending on the way the values are calculated.

Comparing them directly can be useful too if you can absolutely ensure that such errors are not a problem in your case.

Comparing in the string domain seems unuseful to me.

glglgl
  • 89,107
  • 13
  • 149
  • 217
1

dbVal1 == dbVal2 is not the same as the String version because of NaN.

double a = 0.0 / 0.0;
double b = 0.0 / 0.0;
System.out.println(a == b);    // false
System.out.println(Double.toString(a).equals(Double.toString(b)));    // true

I think the person who wrote this code wanted NaN to equal NaN.

Paul Boddington
  • 37,127
  • 10
  • 65
  • 116
  • I just saw this case in trying to test. But Double.compare(double, double) seems to make this work. Any reasons not to use that method? – Andrew Wirtz Mar 10 '15 at 19:47
  • @AndrewWirtz You're right. I've only shown that `a == b` isn't the same as the `String` version. I've edited my answer accordingly. I need to think about `Double.compare()`. – Paul Boddington Mar 10 '15 at 19:50
  • Don't forget `0.0` and `-0.0`. – Marco13 Mar 10 '15 at 20:06
  • @Marco13 There's lots of things to consider, `Infinity`, `-Infinity` as well. I think that that `Double.compare(a, b) == 0` is always the same as `Double.toString(a).equals(Double.toString(b))`. I wouldn't like to assert that for sure in an answer though, – Paul Boddington Mar 10 '15 at 20:14
  • 1
    `+/-Infinity` should not be a problem. I can't think of any other case where the behavior is different (and actually tried out some border cases close to `MAX_VALUE` etc.). Nevertheless, comparing doubles as Strings is a horrible, horrible idea anyhow, so let's hope these border cases will not be relevant for the asker at all. – Marco13 Mar 10 '15 at 20:23
1

The class Double provides a compare method that treats NaNs as being equal. I have tested several of the interesting cases, and in each case it gave the same result as the more indirect String method:

public class Test {
  public static void main(String[] args) {
    testit(0.0,0.0);
    testit(0.0, -0.0);
    testit(Double.NaN, Double.NaN);
    testit(Double.NaN, 3.0);
    testit(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
    testit(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
  }

  private static void testit(double a, double b) {
    boolean doubleEquals = (a == b);
    boolean doubleCompare = Double.compare(a, b) == 0;
    boolean stringCompare = Double.toString(a).compareTo(Double.toString(b)) == 0;
    if(doubleCompare != stringCompare){
      System.out.print("* ");
    }
    System.out.println("a=" + a + " b=" + b + " double == " + doubleEquals
        + " Double compare " + doubleCompare + " String compare "
        + stringCompare);
  }
}

Output:

a=0.0 b=0.0 double == true Double compare true String compare true
a=0.0 b=-0.0 double == true Double compare false String compare false
a=NaN b=NaN double == false Double compare true String compare true
a=NaN b=3.0 double == false Double compare false String compare false
a=Infinity b=Infinity double == true Double compare true String compare true
a=-Infinity b=-Infinity double == true Double compare true String compare true
Patricia Shanahan
  • 25,849
  • 4
  • 38
  • 75
0

The fastest way would be, of course, leaving double variables as they are and comparing them. Autoboxing, using methods, if-else are unnecessary burden to the CPU.

Trynkiewicz Mariusz
  • 2,722
  • 3
  • 21
  • 27