Why does Math.round(0.49999999999999994) return 1? Why does Math.round(0.49999999999999994) return 1? java java

Why does Math.round(0.49999999999999994) return 1?


Summary

In Java 6 (and presumably earlier), round(x) is implemented as floor(x+0.5).1 This is a specification bug, for precisely this one pathological case.2 Java 7 no longer mandates this broken implementation.3

The problem

0.5+0.49999999999999994 is exactly 1 in double precision:

static void print(double d) {    System.out.printf("%016x\n", Double.doubleToLongBits(d));}public static void main(String args[]) {    double a = 0.5;    double b = 0.49999999999999994;    print(a);      // 3fe0000000000000    print(b);      // 3fdfffffffffffff    print(a+b);    // 3ff0000000000000    print(1.0);    // 3ff0000000000000}

This is because 0.49999999999999994 has a smaller exponent than 0.5, so when they're added, its mantissa is shifted, and the ULP gets bigger.

The solution

Since Java 7, OpenJDK (for example) implements it thus:4

public static long round(double a) {    if (a != 0x1.fffffffffffffp-2) // greatest double value less than 0.5        return (long)floor(a + 0.5d);    else        return 0;}

1. http://docs.oracle.com/javase/6/docs/api/java/lang/Math.html#round%28double%29

2. http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6430675 (credits to @SimonNickerson for finding this)

3. http://docs.oracle.com/javase/7/docs/api/java/lang/Math.html#round%28double%29

4. http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/java/lang/Math.java#Math.round%28double%29


Source code in JDK 6:

public static long round(double a) {    return (long)Math.floor(a + 0.5d);}

Source code in JDK 7:

public static long round(double a) {    if (a != 0x1.fffffffffffffp-2) {        // a is not the greatest double value less than 0.5        return (long)Math.floor(a + 0.5d);    } else {        return 0;    }}

When the value is 0.49999999999999994d, in JDK 6, it will call floor and hence returns 1, but in JDK 7, the if condition is checking whether the number is the greatest double value less than 0.5 or not. As in this case the number is not the greatest double value less than 0.5, so the else block returns 0.

You can try 0.49999999999999999d, which will return 1, but not 0, because this is the greatest double value less than 0.5.