PhilDin
PhilDin

Reputation: 2842

Why is BigDecimal not rounded as expected

The code below divides 1620 by 100 and gets a result of 16.00 instead of the expected value of 16.20.

MathContext mc = new MathContext(2, RoundingMode.HALF_EVEN);

BigDecimal num = new BigDecimal("1620").setScale(2, RoundingMode.HALF_EVEN);
BigDecimal divider = new BigDecimal(100).setScale(2,RoundingMode.HALF_EVEN);

BigDecimal result = num.divide(divider, mc).setScale(2, RoundingMode.HALF_EVEN);

Printing out the values above I get

num: 1620.00 divider 100.00 result: 16.00

If I change the precision in the MathContext to 4, I get a result of 16.20 but why? Should a precision of 2 in the MathContext not result in 16.20?

Upvotes: 1

Views: 367

Answers (4)

Heaven42
Heaven42

Reputation: 329

BigDecimal num = new BigDecimal("1620").setScale(2, RoundingMode.HALF_EVEN);
BigDecimal divider = new BigDecimal(100).setScale(2,RoundingMode.HALF_EVEN);

BigDecimal result = num.divide(divider).setScale(2,RoundingMode.HALF_EVEN);

Just have five minutes to finish my answer in your case, you were setting a precision of 2 by setting the MathContext ( JAVADOC ) MathContext(int precision,RoundingMode setRoundingMode).

Precision of 2 so only two digits.

Hope that's help

Upvotes: 2

SJuan76
SJuan76

Reputation: 24780

Precission specifies the total number of significant digits, not of digits right of the point.

Check this code

MathContext mContext = new MathContext(2);
BigDecimal bd1 = new BigDecimal(1234, mContext);
BigDecimal bd2 = new BigDecimal(10, mContext);
System.out.println("Big " + bd1.divide(bd2).toPlainString()); // returns 120

This makes sense, since the position of the decimal point is just an issue of scale 12.34 is the same than 1.234+E1 and 123.4-E1.

Upvotes: 2

ClickerMonkey
ClickerMonkey

Reputation: 1931

When you pass 2 to the constructor of MathContext, you are apparently restricting some of the intermittent values calculated for division. I don't know whether this is intended by the API... I would guess not. Appears to be a bug.

Nonetheless you have a few options.

  1. Change the 2 to a 4 in the constructor of MathContext and everything works.
  2. Remove the setScale and MathContext from your code, simplifying it and making it more accurate. If you're always setting the scale you could be chopping of significant digits depending on the input. Add the precision and rounding mode straight into your division operations.

Code Example:

 BigDecimal num = new BigDecimal("1620");
 BigDecimal divider = new BigDecimal(100);
 BigDecimal result = num.divide(divider, 2, RoundingMode.HALF_EVEN);

That gives me 16.20.

Upvotes: -1

Arjen
Arjen

Reputation: 309

It has to do with the total number of digits. Use round() instead of setScale().

Upvotes: 0

Related Questions