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
Converting Many 'If Else' Statements to a Cleaner Approach
Ideal Method to Truncate a String with Ellipsis
Regular Expression with Variable Number of Groups
How to Force Selenium Webdriver to Click on Element Which Is Not Currently Visible
How to Read PDF Files Using Java
Difference Between Java Se/Ee/Me
Use Cases and Examples of Gof Decorator Pattern for Io
How to Map a Postgresql Array with Hibernate
Putting Char into a Java String for Each N Characters
Why Is String Immutable in Java
@Runwith(Mockitojunitrunner.Class) VS Mockitoannotations.Initmocks(This)
Jcombobox Selection Change Listener
How to Show/Hide a Column at Runtime
Post Request Send JSON Data Java Httpurlconnection
Purpose of Default or Defender Methods in Java 8
How to Convert a Java 8 Stream to an Array
How to Change the Intellij Idea Default Jdk
What Is the Significance of Url-Pattern in Web.Xml and How to Configure Servlet