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
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