0

I am facing simple issue in below program. In below code I am just subtracting numbers and expected output is "89.50" but it is printing 90. May I know the reason and help me with code to get expected output.

public class BigDecimal_Prb {

  public static void main(String[] args) throws java.lang.Exception
  {
    MathContext mc = new MathContext(2); 
    List<BigDecimal> list = new ArrayList<BigDecimal>();
    list.add(BigDecimal.valueOf(30));
    list.add(BigDecimal.valueOf(120.00));

    BigDecimal [] nums = (BigDecimal[]) list.toArray(new BigDecimal[0]);
    BigDecimal reaminingAmt=nums[1].subtract(nums[0], mc);
    BigDecimal dedAmt=new BigDecimal(0.5);
    BigDecimal ans = reaminingAmt.subtract(dedAmt,mc);
    System.out.println(ans);
  }
}
Raghu
  • 59
  • 3
  • 17
  • You should probably use `BigDecimal("0.5")` rather than `BigDecimal(0.5)`. – John Coleman Oct 14 '17 at 13:38
  • Also, I think that you misunderstand `MathContext` It isn't the number of decimal places, it is the number of digits period. A math context of 2 isn't big enough to hold `89.5`. See https://stackoverflow.com/q/7539/4996248 – John Coleman Oct 14 '17 at 13:44
  • Possible duplicate of [Use of java.math.MathContext](https://stackoverflow.com/questions/7539/use-of-java-math-mathcontext) – John Coleman Oct 14 '17 at 13:46
  • Thanks for your comments John. I tried with BigDecimal("0.5") but it didn't work. – Raghu Oct 14 '17 at 14:19
  • 1
    The more fundamental problem is the `MathContext` usage. – John Coleman Oct 14 '17 at 15:00

2 Answers2

1

Subtraction certainly works, but the other things you do cause the "unexpected" result.

A MathContext contains two main elements: a precision and a rounding mode. I guess you understood the rounding mode, but not the precision.

The precision is the number of significant digits of a BigDecimal. In other words, if you set it to 2, you can expect the number to be rounded to two digits, i.e. 90. If you want a certain number of digits after the decimal point, use the scale:

BigDecimal ans = reaminingAmt.subtract(dedAmt).setScale(2);
Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
0

yes. Finally got it.

No it's not a scaling issue. The "solution" I found has the side-effect of changing the result of the BigDecimal.toString() method. However, the intent of setScale() is to fine-tune the results of internal calculations performed on the BigDecimal value. If you only want the scale of your BigDecimal to be 2 because that's all you need for calculation results to be acceptable, that's fine, set the scale. But if you're using setScale() so that your output will show "120.00" instead of "120.0," then you're using the wrong approach and doing it for the wrong reasons, IMO.

If you need the scale of 2, change all your instance creations to use the BigDecimal(String) constructor. That will retain the .00 part, and you will then get the scale of 2 you have been looking for.

public class BigDecimal_Prb {

public static void main(String[] args) throws java.lang.Exception
   {
    MathContext mc = new MathContext(4, RoundingMode.HALF_DOWN); 
    List<BigDecimal> list = new ArrayList<BigDecimal>();
    list.add(BigDecimal.valueOf(30));
    list.add(BigDecimal.valueOf(120.00));

    BigDecimal [] nums = (BigDecimal[]) list.toArray(new BigDecimal[0]);
    BigDecimal reaminingAmt=nums[1].subtract(nums[0], mc);
    BigDecimal dedAmt=new BigDecimal(0.5);
    BigDecimal ans = reaminingAmt.subtract(dedAmt,mc).setScale(2, RoundingMode.HALF_DOWN);
    System.out.println(ans.toString());
   }
}
Raghu
  • 59
  • 3
  • 17