Home > Software engineering >  BigDecimal setScale ROUND_HALF_UP don't seem to operate on each number
BigDecimal setScale ROUND_HALF_UP don't seem to operate on each number

Time:06-18

When I ROUND_HALF_UP 10.12445 with scale 2, I expect to get 10.13, because 10.12445 -> 10.1245 -> 10.125 -> 10.13 But the result is 10.12

BigDecimal b = new BigDecimal("10.12445");
b = b.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("10.12445 scale 2 : "   b);  // 10.12

Therfore if I succesively round with scales 4, 3 and 2, I get the result that I expect:

BigDecimal a = new BigDecimal("10.12445");
a = a.setScale(4, BigDecimal.ROUND_HALF_UP);
System.out.println("10.12445 scale 4 : "   a); //10.1245
a = a.setScale(3, BigDecimal.ROUND_HALF_UP);
System.out.println("10.1245 scale 3 : "   a); //10.125
a = a.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("10.125 scale 2 : "   a); //10.13

Did I miss something?

Is there a way to get the result I expect directly?

CodePudding user response:

HALF_UP:

Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round up. Behaves as for RoundingMode.UP if the discarded fraction is ≥ 0.5; otherwise, behaves as for RoundingMode.DOWN.

This rounding mode rounds towards the nearest neighbour, and only if the neighbours are equally near do we do something different. For the scale 2, the neighbours of 10.12445 are 10.12 and 10.13. Which is nearer? Are they equally near?

10.13 - 10.12445 = 0.00555
10.12445 - 10.12 = 0.00445

Clearly 10.12 is nearer, so that is the result.

The sort of rounding that you are looking for seems to be applying HALF_UP repeatedly, rounding one decimal place at a time, until the scale is 2:

var number = new BigDecimal("10.12445");
for (int i = number.scale() ; i >= 2 ; i--) {
    number = number.setScale(i, RoundingMode.HALF_UP);
}

which is a rather weird way of rounding, and gives some unintuitive (at least to me) results.

CodePudding user response:

It's doing what it's supposed to: using scale 2 means "round this number based on what it is after shifting the decimal point". So we have 10.12445, we treat it as 1012.445 and apply HALF_UP rounding. 1012.445 is less than 1012.5, and so it gets rounded down 1012, thus giving us 10.12

As per the docs:

Returns a BigDecimal whose scale is the specified value, and whose unscaled value is determined by multiplying or dividing this BigDecimal's unscaled value by the appropriate power of ten to maintain its overall value.

  • Related