United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-4508009 : rounding error in BigDecimal.setScale

Details
Type:
Bug
Submit Date:
2001-09-27
Status:
Closed
Updated Date:
2001-10-02
Project Name:
JDK
Resolved Date:
2001-10-02
Component:
core-libs
OS:
generic
Sub-Component:
java.math
CPU:
generic
Priority:
P2
Resolution:
Not an Issue
Affected Versions:
1.4.0
Fixed Versions:

Related Reports

Sub Tasks

Description

Name: nt126004			Date: 09/27/2001


java version "1.4.0-beta2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta2-b77)
Java HotSpot(TM) Client VM (build 1.4.0-beta2-b77, mixed mode)


java.math.BigDecimal using ROUND_HALF_UP does not behave as expected

i.e

import java.math.*;
public class BigTest {
public static void main(String[] args) {

    BigDecimal bd = new BigDecimal(0.115);
    bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
    System.out.println("? 0.12 = " + bd);

    bd = new BigDecimal(1.115);
    bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
    System.out.println("? 1.12 = " + bd);

    bd = new BigDecimal(2.115);
    bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);

    System.out.println("? 2.12 = " + bd);
}
}



output:

? 0.12 = 0.12
? 1.12 = 1.11
? 2.12 = 2.12

should be:

? 0.12 = 0.12
? 1.12 = 1.12
? 2.12 = 2.12


(Review ID: 132704) 
======================================================================

                                    

Comments
WORK AROUND

Using the string constructor instead of the double constructor avoids the numerical surprise occuring here.
                                     
2004-06-11
PUBLIC COMMENTS

A side-effect of floating-point decimal -> binary conversion is being seen.  The value indicated by the decimal string is not exactly representable.  Using the string constructor instead avoids this particular issue.

###@###.### 2001-10-01
                                     
2001-10-01
EVALUATION

The "problem" in this bug is that the code is using the BigDecimal double construtor instead of the BigDecimal string constructor.  The exact value of a decimal floating-point literal (like "0.115") generally cannot be stored in a floating-point number since floating-point numbers use base 2 instead of base 10.  Instead of the exact value of the literal, you get a value that is very close; for the values in question:

0.115d is exactly 0.11500000000000000499600361081320443190634250640869140625
1.115d is exactly 1.1149999999999999911182158029987476766109466552734375
2.115d is exactly 2.1150000000000002131628207280300557613372802734375

These exact double values are then converted to BigDecimal (all finite binary floating-point values can be exactly represented as BigDecimals) as described in the BigDecimal class documetnation.  Now, it is easy to see why the given output was observed; using the string constructor gives the "expected" results.

This issue is explicitly discussed in the BigDecimal documentation for the double constructor:

"Translates a double into a BigDecimal. The scale of the BigDecimal is the smallest value such that (10scale * val) is an integer. 

Note: the results of this constructor can be somewhat unpredictable. One might assume that new BigDecimal(.1) is exactly equal to .1, but it is actually equal to .1000000000000000055511151231257827021181583404541015625. This is so because .1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the long value that is being passed in to the constructor is not exactly equal to .1, appearances nonwithstanding. 

The (String) constructor, on the other hand, is perfectly predictable: new BigDecimal(".1") is exactly equal to .1, as one would expect. Therefore, it is generally recommended that the (String) constructor be used in preference to this one. "

See "What Everybody Using the JavaTM Programming Language Should Know About Floating-Point Arithmetic"
http://java.sun.com/people/darcy/JavaOne/2001/1789darcy.pdf
for further discussion of Java numerics issues.

Closing as not a bug.

###@###.### 2001-10-01
                                     
2001-10-01



Hardware and Software, Engineered to Work Together