how does java.math.RoundingMode work?
Rounding mode use for Round the Decimal Value.
You can use with.
double DecimalValue = 3.1452;
BigDecimal decimal = new BigDecimal(DecimalValue).setScale(2, RoundingMode.DOWN);
=>
RoundingMode.CEILING
Rounding mode to round towards positive infinity. For
positive values this rounding mode behaves as UP, for
negative values as DOWN.
Rule: x.round() >= x
RoundingMode.DOWN
Rounding mode where the values are rounded towards
zero.
Rule: x.round().abs() <= x.abs()
RoundingMode.DOWN
Rounding mode to round towards negative infinity. For
positive values this rounding mode behaves as DOWN, for
negative values as UP.
Rule: x.round() <= x
RoundingMode.HALF_DOWN
Rounding mode where values are rounded towards the nearest neighbor. Ties are broken by rounding down.
RoundingMode.HALF_EVEN
Rounding mode where values are rounded towards the nearest neighbor. Ties are broken by rounding to the even neighbor.
RoundingMode.HALF_UP
Rounding mode where values are rounded towards the nearest neighbor. Ties are broken by rounding up.
RoundingMode.UNNECESSARY
Rounding mode where the rounding operations throws an
ArithmeticException
for the case that rounding is
necessary, i.e. for the case that the value cannot be
represented exactly.
RoundingMode.UP
Rounding mode where positive values are rounded
towards positive infinity and negative values towards
negative infinity.
Rule: x.round().abs() >= x.abs()
@Peter Lawrey I looked at your examples and wrote a quick program comparing the simple approach that you posted along with all the methods for RoundingMode. The code is here for anyone interested, this will clearly show the differences:
[RoundingMode.java] https://gitlab.com/bobby.estey/java/-/blob/master/maven/jdk14/src/main/java/mathematics/RoundingModeExamples.java
Results:
lowDouble: 1.55553
simple - lowDouble: 1.5555
RoundingMode.UP - lowDouble: 1.5556
RoundingMode.DOWN - lowDouble: 1.5555
RoundingMode.CEILING - lowDouble: 1.5556
RoundingMode.FLOOR - lowDouble: 1.5555
RoundingMode.HALF_UP - lowDouble: 1.5555
RoundingMode.HALF_DOWN - lowDouble: 1.5555
RoundingMode.HALF_EVEN - lowDouble: 1.5555
highDouble: 1.55555
simple - highDouble: 1.5556
RoundingMode.UP - highDouble: 1.5556
RoundingMode.DOWN - highDouble: 1.5555
RoundingMode.CEILING - highDouble: 1.5556
RoundingMode.FLOOR - highDouble: 1.5555
RoundingMode.HALF_UP - highDouble: 1.5555
RoundingMode.HALF_DOWN - highDouble: 1.5555
RoundingMode.HALF_EVEN - highDouble: 1.5555
0.555d
is a double
value. It may be slightly larger than 0.555 or slightly smaller.
The problem you have is that double is not a precise representation and you are round based on this imprecise number.
BigDecimal bd = new BigDecimal(1.555d);
System.out.println("bd=" + bd);
bd = bd.setScale(2, RoundingMode.HALF_UP);
System.out.println("after rounding bd=" + bd);
double d = bd.doubleValue();
System.out.println("after rounding d=" + d);
prints
bd=1.5549999999999999378275106209912337362766265869140625
after rounding bd=1.55
after rounding d=1.55
however
BigDecimal bd = BigDecimal.valueOf(1.555d);
System.out.println("bd=" + bd);
bd = bd.setScale(2, RoundingMode.HALF_UP);
System.out.println("after rounding bd=" + bd);
double d = bd.doubleValue();
System.out.println("after rounding d=" + d);
prints
bd=1.555
after rounding bd=1.56
after rounding d=1.56
This works because BigDecimal.valueOf
does some extra rounding based on how double would appear if you printed it.
However I wouldn't use BigDecimal unless performance/simplicity is not an issue.
double d = 1.555d;
System.out.println("d=" + d);
d = roundToTwoPlaces(d);
System.out.println("after rounding d=" + d);
public static double roundToTwoPlaces(double d) {
return ((long) (d < 0 ? d * 100 - 0.5 : d * 100 + 0.5)) / 100.0;
}
prints
d=1.555
after rounding d=1.56
For more details Double your money again compares the performance of different ways of rounding.