3

I'm trying to get predictable behavior with rounding BigDecimal numbers to 15th digit. As a result I'm getting some either round up or round down.

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;

public class NumberTest {
    public static void main(String[] args) {
        String pattern = "##############0.0##############";
        MathContext mc = new MathContext(15, RoundingMode.HALF_UP);
        NumberFormat numberFormat = new DecimalFormat(pattern);

        BigDecimal n1 = new BigDecimal(0.0452641706926935, mc);
        n1.setScale(15, BigDecimal.ROUND_HALF_UP);
        BigDecimal n2 = new BigDecimal(0.0123456789012345, mc);
        n2.setScale(15, BigDecimal.ROUND_HALF_UP);

        System.out.println("n1: "+n1+" ==> "+n1.doubleValue()+"="+numberFormat.format(n1.doubleValue()));
        System.out.println("n3: "+n2+" ==> "+n2.doubleValue()+"="+numberFormat.format(n2.doubleValue()));
    }
}

Output of my result:
n1: 0.0452641706926935 ==> 0.0452641706926935=0.045264170692694
n2: 0.0123456789012345 ==> 0.0123456789012345=0.012345678901234

n1 - rounded up n2 - rounded down

What am I missing?

thank you.

shoelzer
  • 10,648
  • 2
  • 28
  • 49
dgene00
  • 31
  • 1
  • 2
  • 1
    Why are you passing in a limited precision floating point value instead of the string form: `"0.0452..."`? – Mike Samuel Aug 26 '14 at 15:42
  • I'm getting my BigDecimals from database. They come out like that from ResultSet. – dgene00 Aug 26 '14 at 15:45
  • I've just tried it with strings and got the same result. – dgene00 Aug 26 '14 at 15:46
  • Not sure what "rounding BigDecimal numbers" is supposed to mean. The output of your program is strings, and the strings come from either one of two places: Either you implicitly call Double.toString(d), or your call numberFormat.format(d) where d is a _double_ in either case. The BigDecimal objects don't even enter in to the picture. – Solomon Slow Aug 26 '14 at 16:06

4 Answers4

4

You're not actually using the BigDecimal for which you set the scale:

n2.setScale(15, BigDecimal.ROUND_HALF_UP);

This line should be:

n2 = n2.setScale(15, BigDecimal.ROUND_HALF_UP);

Change to that and it works as expected.

user1676075
  • 3,056
  • 1
  • 19
  • 26
1
n2: 0.0123456789012345 ==> 0.0123456789012345=0.012345678901235

No, n2 is perfectly rounded up , the 15th digit on n2 after dot . is 4 followed by 5 , so 45 is rounded up to 5.

if you count number of digits on n2 after . they are 16 digits not 15 so according to your pattern you want to round up for 15 digit length after dot .

btw you don't need to care about amount of digits before . by using "##############0.0##############", you can simply use ".###############".

Fevly Pallar
  • 3,059
  • 2
  • 15
  • 19
1

You're setting the rounding mode for the BigDecimal. But what is rounding the last part of your output is not the BigDecimal. It's the DecimalFormat.

Set the rounding mode of the DecimalFormat:

numberFormat.setRoundingMode(RoundingMode.HALF_UP);

Note that DecimalFormat is able to format DecimalFormat instances. You shouldn't transform them to double before formatting them, since you could lose precision by doing that.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
1

From the Java documentation of MathContext:

The base-independent settings are:
precision: the number of digits to be used for an operation; results are rounded to this precision
roundingMode: a RoundingMode object which specifies the algorithm to be used for rounding.

You don't do any operation here, so your BigInteger object are not rounded. Therefore, when you print your values, n1 and n2 still contain your initial values with 16 digits.

Then, I guess you obtain rounding errors because of the format method. It takes a double as an argument, which will never be exactly the 16 digits you used, but only an approximation. Because it is an approximation, n2 might have been stored as ...23449 instead of ...2345.

But like Fev, I am not getting this error when executing your program on my computer.

R2B2
  • 1,541
  • 1
  • 12
  • 19