java. math. How does roundingmode work?
I'm having trouble rounding Specifically, after reading all the JavaDocs, I look forward to the following code:
int n = (integer between 0 and 9,included) new BigDecimal(n + 0.555d).setScale(2,RoundingMode.HALF_UP).doubleValue()
Returns n 0.56 Instead, these are the return values of N from 0 to 4:
new BigDecimal(0.555d).setScale(2,RoundingMode.HALF_UP).doubleValue() 0.56 new BigDecimal(1.555d).setScale(2,RoundingMode.HALF_UP).doubleValue() 1.55 new BigDecimal(2.555d).setScale(2,RoundingMode.HALF_UP).doubleValue() 2.56 new BigDecimal(3.555d).setScale(2,RoundingMode.HALF_UP).doubleValue() 3.56 new BigDecimal(4.555d).setScale(2,RoundingMode.HALF_UP).doubleValue() 4.55
I also try to change the rounding mode:
int n = (integer between 0 and 9,RoundingMode.HALF_DOWN).doubleValue()
The result of each n is expected to be n 0.55 Instead, the return value is exactly the same as the previous example:
new BigDecimal(0.555d).setScale(2,RoundingMode.HALF_DOWN).doubleValue() 0.56 new BigDecimal(1.555d).setScale(2,RoundingMode.HALF_DOWN).doubleValue() 1.55 new BigDecimal(2.555d).setScale(2,RoundingMode.HALF_DOWN).doubleValue() 2.56 new BigDecimal(3.555d).setScale(2,RoundingMode.HALF_DOWN).doubleValue() 3.56 new BigDecimal(4.555d).setScale(2,RoundingMode.HALF_DOWN).doubleValue() 4.55
Did I miss anything?
Solution
The problem you encounter is that double is not an exact representation. 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);
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);
bd=1.555 after rounding bd=1.56 after rounding d=1.56
This is valid because BigDecimal Valueof makes some additional rounding based on the double that appears when printing
However, I won't use BigDecimal unless performance / simplicity is not a problem
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; }
d=1.555 after rounding d=1.56
For more details, double your money again compares the performance of different rounding methods