Search code examples
javadoublerounding

Nearest multiple of a power of two fraction


Is there an optimized, performant way to round a double to the exact value nearest multiple of a given power of two fraction?

In other words, round .44 to the nearest 1/16 (in other words, to a value that can be expressed as n/16 where n is an integer) would be .4375. Note: this is relevant because power of two fractions can be stored without rounding errors, e.g.

public class PowerOfTwo {
  public static void main(String... args) {
    double inexact = .44;
    double exact = .4375;

    System.out.println(inexact + ":   " + Long.toBinaryString(Double.doubleToLongBits(inexact)));
    System.out.println(exact + ": " + Long.toBinaryString(Double.doubleToLongBits(exact)));
  }
}

Output:

0.44:   11111111011100001010001111010111000010100011110101110000101001
0.4375: 11111111011100000000000000000000000000000000000000000000000000

Solution

  • If you want to chose the power of two, the simplest way is to multiply by e.g. 16, round to nearest integer, then divide by 16. Note that division by a power of two is exact if the result is a normal number. It can cause rounding error for subnormal numbers.

    Here is a sample program using this technique:

    public class Test {
      public static void main(String[] args) {
        System.out.println(roundToPowerOfTwo(0.44, 2));
        System.out.println(roundToPowerOfTwo(0.44, 3));
        System.out.println(roundToPowerOfTwo(0.44, 4));
        System.out.println(roundToPowerOfTwo(0.44, 5));
        System.out.println(roundToPowerOfTwo(0.44, 6));
        System.out.println(roundToPowerOfTwo(0.44, 7));
        System.out.println(roundToPowerOfTwo(0.44, 8));
      }
    
      public static double roundToPowerOfTwo(double in, int power) {
        double multiplier = 1 << power;
        return Math.rint(in * multiplier) / multiplier;
      }
    }
    

    Output:

    0.5
    0.5
    0.4375
    0.4375
    0.4375
    0.4375
    0.44140625