Skip to content
Advertisement

BigDecimal setScale ROUND_HALF_UP don’t seem to operate on each number

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?

Advertisement

Answer

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.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement