Tuesday, December 29, 2009

Rounding doubles in Java

Strangely enough there is no standard way in Java to round double values up to a certain order of 10 or 2. There are some ways to do that, but they seem to be too bulky and, maybe, not fast enough. For example, the one where you have to use BigDecimal, it seems to be too much of an overkill to create a new object only to round a value.

After spending a little bit of time studying methods offered by standard java.lang.Math class I stumbled upon two methods that in combination would allow me to round values up to a power of two.

double Math.scalb(double value) - multiplies given double value by the given power of two,
double Math.iround(double value) - discards everything to the right of the decimal point.

So here's what needs to be done:
  1. Divide the given double value by the given power of two.
  2. Discard the decimal part.
  3. Multiply the result by the given power of two.
But there is a catch that you should know about; resulting value may still have something below given precision point, that's OK. As in fact what this method does is setting granularity up to the given power of two.
Here's the method:
public static double round(double value, int power) {
  // Divide value by 2^power
  double scaled = Math.scalb(value, -power);
  // Discard the fractional part, multiply back by 2^power
  return Math.scalb(Math.rint(scaled), power);
This approach is great when you compare Doubles with tolerance and need equal hash codes for equal values.

Don't forget that rounding is done up to a certain power of two:
Powers of two.Values that the fractional part may assume.
-20.25, 0.5, 0.75
-30.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875

No comments: