Search code examples
bigdecimaljava

BigDecimal, division & MathContext - very strange behaviour


CentOs 5.4, OpenJDK Runtime Environment (build 1.6.0-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 ?


Solution

  • 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.