Reputation: 53
I am seeing some strange behavior in trying to round doubles to 2 decimal places
Below is the code
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setRoundingMode(RoundingMode.HALF_EVEN);
double f1 = 100.845;
double f2 = 1440.845;
System.out.println( df.format(f1));
System.out.println( df.format(f2));
This outputs
100.84
1,440.85
I was expecting 100.85 for the first value.
As I was looking into it further, I found the following
101.845 --> 100.84
102.845 --> 102.84
103.845 --> 103.84
.
.
255.845 --> 255.84
**256.845 --> 256.85**
257.845 --> 256.85
.
.
I am thinking it must have something to do with the precision as the switch from .84 to .85 occurred around 255( 2^8 -1). But, I am not calculating this value( at least not in this sample code).
Can anyone shed some light on why this is happening?
Thank you
Upvotes: 0
Views: 114
Reputation: 21094
The issue here is due to the fact that neither of these double values are exactly equal to the decimal representation used in the Java code; they're instead a close floating point value.
The following is one way to print their exact values:
System.out.println(new BigDecimal(100.845));
System.out.println(new BigDecimal(1440.845));
This outputs:
100.844999999999998863131622783839702606201171875
1440.845000000000027284841053187847137451171875
100.8449...
rounds down to 100.84
, since it's closest to 100.84
.
1440.8450...
rounds up to 100.85
, since it's closest to 100.85
.
In neither of these cases does the half-even logic apply, since neither number is exactly halfway between two potential rounding targets.
By contrast, if you use a number format that can exactly represent these values (such as BigDecimal
), you'll see the expected rounding:
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setRoundingMode(RoundingMode.HALF_EVEN);
BigDecimal d1 = new BigDecimal("100.845");
BigDecimal d2 = new BigDecimal("1440.845");
System.out.println( df.format(d1));
System.out.println( df.format(d2));
Output:
100.84
1,440.84
Upvotes: 3
Reputation: 798
When using HALF_EVEN
, it rounds towards the "nearest neighbor" unless both neighbors are equidistant. If they are equidistant, it rounds towards the even neighbor to the left...
In you case, 100.845
the last digit 5
is equidistant so it rounds to the nearest even neighbor to the left 4
.
Here, you are using double
which, in memory, can be sligtly off with the value. To make sure the numbers that you are rouding are not equidistand, add the precision error which is + 1e-6
for your double
.
Upvotes: 0