171

What is the difference between this two call? (Is there any?)

// 1.
new BigDecimal("3.53456").round(new MathContext(4, RoundingMode.HALF_UP));
// 2.
new BigDecimal("3.53456").setScale(4, RoundingMode.HALF_UP);
user
  • 6,567
  • 18
  • 58
  • 85
  • 8
    apart from accepted answers below - setScale() creates a new object of BigDecimal - given its an immutable class – prash Nov 17 '15 at 09:19
  • 11
    @prash the `round` method also returns a new instance of BigDecimal because, as you said, the instances are immutable. – daiscog Nov 18 '16 at 14:46
  • 1
    The difference is you probably almost always want `.setScale` and the other one is a distracting example of academic nomenclature winning out over normal folk. – MarkHu Sep 23 '21 at 00:30

2 Answers2

262

One important point that is alluded to but not directly addressed is the difference between "precision" and "scale" and how they are used in the two statements. "precision" is the total number of significant digits in a number. "scale" is the number of digits to the right of the decimal point.

The MathContext constructor only accepts precision and RoundingMode as arguments, and therefore scale is never specified in the first statement.

setScale() obviously accepts scale as an argument, as well as RoundingMode, however precision is never specified in the second statement.

If you move the decimal point one place to the right, the difference will become clear:

// 1.
new BigDecimal("35.3456").round(new MathContext(4, RoundingMode.HALF_UP));
//result = 35.35
// 2.
new BigDecimal("35.3456").setScale(4, RoundingMode.HALF_UP);
// result = 35.3456
Stephan
  • 16,509
  • 7
  • 35
  • 61
dale peters
  • 2,840
  • 1
  • 16
  • 11
  • 48
    Re: ""precision" is the total number of digits in a number." No. Precision is the number of significant digits. The precision of 0.000042M is 2. – David J. Dec 04 '13 at 04:16
  • 3
    See: "precision": The digit count starts from the leftmost nonzero digit of the exact result. https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html – Eddy Sep 06 '16 at 07:06
  • if "Precision is the number of significant digits" than why precision of 0.0000009 is coming as 2 ? it should be 1 – Sanchi Girotra Oct 24 '16 at 10:10
  • 1
    How is the value of your BigDecimal getting set? How are you outputting the value (using a String.format() might hide significant digits)? – dale peters Oct 25 '16 at 14:58
  • 1
    @SanchiGirotra The precision is "the number of digits in the unscaled value". A precision of 2 with an *unscaled* value of 90 and a scale of 8 gives 0.0000009. As does a precision of 1, unscaled value of 9 and a scale of 7. – daiscog Nov 18 '16 at 14:56
  • That is a case of an unhappy named parameter which leads to confusion. What most people want is to define the decimal precision, not the significant digits, so the method that works in that common understanding of "decimal precision" is the setScale(), avoid the MathContext, only leads to confusion and potential bugs in your code. Change 35.3456 for 3333335.3456 and you will get something you don't expect by using MathContext(4, ..), and the expected result for setScale(4, ..) – Pablo Pazos Sep 16 '21 at 23:46
  • @PabloPazos What is the unexpected result of that example? You have to tell me after all these years. – user Jan 17 '22 at 12:35
54

There is indeed a big difference, which you should keep in mind. setScale really set the scale of your number whereas round does round your number to the specified digits BUT it "starts from the leftmost digit of exact result" as mentioned within the jdk. So regarding your sample the results are the same, but try 0.0034 instead. Here's my note about that on my blog:

http://araklefeistel.blogspot.com/2011/06/javamathbigdecimal-difference-between.html

user817756
  • 549
  • 5
  • 2