BigDecimal, division & MathContext - very strange behaviour
CentOs 5.4, OpenJDK Runtime Environment (build 1.6.0开发者_JAVA百科-b09)
MathContext context = new MathContext(2, RoundingMode.FLOOR);
BigDecimal total = new BigDecimal("200.0", context);
BigDecimal goodPrice = total.divide(BigDecimal.valueOf(3), 2, RoundingMode.FLOOR);
System.out.println("divided price=" + goodPrice.toPlainString());
// prints 66.66
BigDecimal goodPrice2 = total.divide(BigDecimal.valueOf(3), new MathContext(2, RoundingMode.FLOOR));
System.out.println("divided price2=" + goodPrice2.toPlainString());
// prints 66
BUG ?
Javadoc for the first situation:
Returns a BigDecimal whose value is (this / divisor), and whose scale is as specified. If rounding must be performed to generate a result with the specified scale, the specified rounding mode is applied.
and the Javadoc for the second situation:
Returns a BigDecimal whose value is (this / divisor), with rounding according to the context settings.
referring to the javadoc for MathContext we get:
Immutable objects which encapsulate the context settings which describe certain rules for numerical operators, such as those implemented by the BigDecimal class. 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.
So in the first case, you specified a SCALE of 2, meaning that you round to 2 decimal places of accuracy, where the rounding is performed as a floor function. The second calculation has a specified PRECISION of 2, which is rounded to two digits of accuracy, where the rounding is a floor function. So, in the first case, you asked for 2 digits after the decimal place, and in the second, you just asked for 2 digits. If, for example, you had asked for 4 digits in your MathContext, you'd get 66.66 as you answer.
So I don't think that this is a bug so much as that the two methods don't perform the same calculation.
This is completely the expected behavior. I think you make the mistake and mix rounding(scale) and precision.
total.divide(BigDecimal.valueOf(3), 2, RoundingMode.FLOOR)
here you override your the MathContext and use a rounding.
total.divide(BigDecimal.valueOf(3), new MathContext(2, RoundingMode.FLOOR))
here you set a precision of 2 and receive only 2 digits.
Reading the Javadoc for the divide(BigDecimal, MathContext) method, it seems that only the rounding mode of the context is taken into account.
精彩评论