views:

208

answers:

3

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 ?

A: 

Reading the Javadoc for the divide(BigDecimal, MathContext) method, it seems that only the rounding mode of the context is taken into account.

matt b
+3  A: 

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.

Scott Fines
+1  A: 

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.

Horcrux7