Using a cast is faster than using floor or round. I suspect a cast is more heavily optimised by the HotSpot compiler.
public class Main {
public static final int ITERS = 1000 * 1000;
public static void main(String... args) {
for (int i = 0; i < 3; i++) {
perfRoundTo3();
perfCastRoundTo3();
}
}
private static double perfRoundTo3() {
double sum = 0.0;
long start = 0;
for (int i = -20000; i < ITERS; i++) {
if (i == 0) start = System.nanoTime();
sum += roundTo3(i * 1e-4);
}
long time = System.nanoTime() - start;
System.out.printf("Took %,d ns per round%n", time / ITERS);
return sum;
}
private static double perfCastRoundTo3() {
double sum = 0.0;
long start = 0;
for (int i = -20000; i < ITERS; i++) {
if (i == 0) start = System.nanoTime();
sum += castRoundTo3(i * 1e-4);
}
long time = System.nanoTime() - start;
System.out.printf("Took %,d ns per cast round%n", time / ITERS);
return sum;
}
public static double roundTo3(double d) {
return Math.round(d * 1000 + 0.5) / 1000.0;
}
public static double castRoundTo3(double d) {
return (long) (d * 1000 + 0.5) / 1000.0;
}
}
prints
Took 22 ns per round
Took 9 ns per cast round
Took 23 ns per round
Took 6 ns per cast round
Took 20 ns per round
Took 6 ns per cast round
Note: as of Java 7 floor(x + 0.5) and round(x) don't do quite the same thing as per this issue. Why does Math.round(0.49999999999999994) return 1
This will round correctly to within the representation error. This means that while the result is not exact the decimal e.g. 0.001 is not represented exactly, when you use toString() it will correct for this. Its only when you convert to BigDecimal or perform an arithmetic operation that you will see this representation error.