Why Does Math.Round(0.49999999999999994) Return 1

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

Why does math.round not round to 2 digits?

Try it using Double

    Dim sum As Double = 535353
Dim vat As Double = Math.Round(sum * 0.19, 2)
Dim total As Double = Math.Round(sum + vat, 2)
' sum 535353.0 Double
' total 637070.07 Double
' vat 101717.07 Double

Strange behavior of Math.round() method

0.49999999999999999 has too many significant digits and one double variable cannot store them all. So implicit rounding happens during compilation. By the time you are calling Math.round(), the argument is already 0.5 (check yourself: 0.49999999999999999 == 0.5 yields true).

Why is Math.round() not rounding up when the value is 0.5?

Due to the way floating points work, the result of (20.49-14.99)*5 is actually 27.499999999999993, which is closer to 27 than 28

Why can't round correctly using Math.round?

I dont see what is wrong with that. Here is the explanantion.

118.64300000000001d * 10L = 1186.43d

Math.round will return the number rounded to the integer part as an long.

Math.round(1186.43d) = 1186L.

1186L / 10.00d = 118.6d

So it looks fine to me. Keep in mind that dividing by a double/float will result in a double/float.



Related Topics



Leave a reply



Submit