Peter is a DZone MVB and is not an employee of DZone and has posted 161 posts at DZone. You can read more from them at their website. View Full User Profile

# Why Math.round (0.499999999999999917) rounds to 1 on Java 6

04.11.2012
| 12895 views |
There are two types of error representation error and arithmetic rounding error which are common in floating point calculations. These two errors combine in this simple example, Math.round(0.499999999999999917) rounds to 1 in Java 6.

## Representation error

Floating point is a base 2 format, which means all number are represented as a sum of powers of 2. e.g. 6.25 is 2^2 + 2^1 + 2^-2. However, even simple numbers like 0.1 cannot be represented exactly. This becomes obvious when converting to BigDecimal as it will preserve the value actually represented without rounding.
```new BigDecimal(0.1)=
0.1000000000000000055511151231257827021181583404541015625
BigDecimal.valueOf(0.1)= 0.1
```
Using the constructor obtains the value actually represented, using valueOf gives the same rounded value you would see if you printed the double When a number is parsed, it is rounded to the closest represented value. This means that there is a number slightly less than 0.5 which will be rounded to 0.5 because it is the closest represented value. The following does a brute force search for the smallest value which rounded becomes 1.0
```public static final BigDecimal TWO = BigDecimal.valueOf(2);

public static void main(String... args) {
int digits = 80;

BigDecimal low = BigDecimal.ZERO;
BigDecimal high = BigDecimal.ONE;

for (int i = 0; i <= 10 * digits / 3; i++) {
BigDecimal mid = low.add(high).divide(TWO, digits, RoundingMode.HALF_UP);
if (mid.equals(low) || mid.equals(high))
break;
if (Math.round(Double.parseDouble(mid.toString())) > 0)
high = mid;
else
low = mid;
}

System.out.println("Math.round(" + low + ") is " +
Math.round(Double.parseDouble(low.toString())));
System.out.println("Math.round(" + high + ") is " +
Math.round(Double.parseDouble(high.toString())));
}
```
The Source Code On Java 7 you get the following result.
```Math.round(0.49999999999999997224442438437108648940920829772949218749999999999999999999999999) is 0
Math.round(0.49999999999999997224442438437108648940920829772949218750000000000000000000000000) is 1
```
What is surprising is that in Java 6 you get the follow.
```Math.round(0.49999999999999991673327315311325946822762489318847656250000000000000000000000000) is 0
Math.round(0.49999999999999991673327315311325946822762489318847656250000000000000000000000001) is 1
```

## Where do these numbers come from?

The Java 7 value is the mid point between 0.5 and the previous represent value. Above this mid point, the value is rounded to 0.5 when parsed. The Java 6 value is the mid point between value value before 0.5 and the value before that.
```Value 0.5 is 0.5
The previous value is 0.499999999999999944488848768742172978818416595458984375
... and the previous is 0.49999999999999988897769753748434595763683319091796875

The mid point between 0.5
and 0.499999999999999944488848768742172978818416595458984375
is 0.4999999999999999722444243843710864894092082977294921875

... and the mid point between 0.499999999999999944488848768742172978818416595458984375
and 0.49999999999999988897769753748434595763683319091796875
is 0.4999999999999999167332731531132594682276248931884765625
```

## Why is the Java 6 value smaller

In the Java 6 Javadoc Math.round(double) is defined as
```(long)Math.floor(a + 0.5d)
```
The problem with this definition is that 0.49999999999999994 + 0.5 has a rounding error which results in the value 1.0. In the Java 7 Javadoc Math.round(double) it simply states
Returns the closest long to the argument, with ties rounding up.

## So how does Java 7 fix this?

The source code for Java 7's Math.round looks like
```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;
}
```
The result for the largest value less than 0.5 is hard coded.

## So what is 0x1.fffffffffffffp-2?

It is a hexi-decimal presentation of the floating point value. It is rarely used, but it is precise as all values can be represented without error (to a limit of 53 bits).