In Android Studio I had problems with calculating invoice totals because of the way java rounds. I know there are a lot of explanations, but many recommend methods that don’t return reliable results.
1. Math.round((double)4.715 * (double)100 ) = 4.72
2. Math.round((double)4.725 * (double)100 ) = 4.72
You can’t put this code in an app for a client who calculates invoices. Because , in my case for example, the same invoice is calculated in another system and the result is different, meaning 4.72 respectively 4.73
I know that a double can’t be represented exactly and the decimals are different than what we see. But we need a method that returns results as we expect.
Another example would be:
1. java.math.BigDecimal.valueOf(4.715).setScale(2,java.math.BigDecimal.ROUND_HALF_UP).doubleValue() = 4.72
2. new java.math.BigDecimal(4.715).setScale(2,java.math.BigDecimal.ROUND_HALF_UP).doubleValue() = 4.71
3. new java.math.BigDecimal( String.valueOf(4.715) ).setScale(2,java.math.BigDecimal.ROUND_HALF_UP).doubleValue() = 4.72
I think all these aspects could be well explained in Java documentation, but they should indicate a certain method for calculating rounds, a reliable method which returns results as we expected. I only wanted to round to 2 decimales.
In conclusion, which I hope will help some of the beginners, I think that the following method would return stable and good results:
java.math.BigDecimal.valueOf(4.715).setScale(2,java.math.BigDecimal.ROUND_HALF_UP).doubleValue() = 4.72
Or, at least, this is my observation after 3+ years of intensive usage of an app (500+ users every working day).
All practical explanations for these above are very welcome, so we can better understand how to avoid unexpected results.
For the BigDecimal examples the javadoc explains the difference.
BigDecimal(double value) … is the exact decimal representation of the double’s binary floating-point value.
Which we can check, by just printing the value.
System.out.println(new BigDecimal(4.715)); #4.714999999999999857891452847979962825775146484375
Which is barely less than 4.715, but enough such that it gets rounded down.
BigDecimal.valueOf(double value) uses the string representation of the double value from Double.toString(double value) which has quite a few rules.
The safest best is to just use BigDecimal for your calculations.