Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java IEEE 64-bit 754 double, values to avoid

I have a situation where performance is extremely important. At the core of my algorithm there is a method that does some basic calculations with two double primitives. This method is called over ten million times per run of the algorithm.

The code looks something like this;

public int compare(double xA, double xB, double yA, double yB);

    double x = xA * xB;
    double y = yA * yB;

    double diff = x - y;

    return (diff < 0.0 ? -1 : (diff > 0.0 ? 1 : 0));

}

The parameters xA and yA take their values from a set. This set can be tweaked in the code. I am seeing huge (approximately double) performance differences depending on the values I put into the set. It seems that if the set contains a 0.1 or a 0.3, the performance takes a big hit. Keeping the set to just multiples of 0.5 gives the best performance.

Is the compiler optimising x * 0.5 as x >> 1 etc? Or is this because 0.1 cannot be defined in binary?

I'd like to understand this situation a bit better so that I can optimise this. I guess it might be quite a hard problem unless someone knows exactly how javac and the jvm (in our case hotspot) handles double multiplication.

like image 759
lynks Avatar asked Nov 14 '22 01:11

lynks


1 Answers

Just a couple few ideas:

  • If values are multiple of 0.5, then there will be few significant bits in the mantissa,so it seems feasible that multiplication takes fewer cicles. Actually significant bits for multiplication doesn't seem to be an issue, since modern processors will take just two cycles for double (as explained in Floating point division vs floating point multiplication).

    E.g. I figure that with 0.5 , 1 , 2, 4 , etc the mantissa will be all zeroes (first "1" is ommited for being implicit). For .75, 1.5, 3 etc, it will be a "1" in the m.s.b. followed by all zeroes. Whereas 0.1 would use all the significand precission to be represented, and even then have an small error.

  • About the result returned: Is there any problem with Math.signum()?. I mean, maybe this would do the same:

    return Math.signum(x-y);
    
  • If precission is not paramount, you might consider using single precission (float). (though if that means you are going to be converting back and forth from double, then it may not be worth it).

like image 119
Javier Avatar answered Dec 18 '22 08:12

Javier