Object num = 12334555578912349.13;
System.out.println(BigDecimal.valueOf(((Number) num).doubleValue()).setScale(2, BigDecimal.ROUND_HALF_EVEN));
I expect the value to be 12334555578912349.13 but output is 123345555789123504.00
How can I prevent it from rounding?
CodePudding user response:
Object num = 12334555578912349.13;
You already lost here. As per the java spec, the literal text '12334555578912349.13' in your source file is interpreted as a double. A double
value, given that computers aren't magic, is a 64-bit value, and thus, only at most 2^64 numbers are even representable by it. Let's call these the 'blessed numbers'. 12334555578912349.13 is not one of the blessed numbers. The nearest blessed number to that is 123345555789123504.0 which is what that value 'compiles' to. Once you're at 123345555789123504.0, there's no way back.
The solution then is to never have '12334555578912349.13' as literal in your source file, as that immediately loses you the game if you do that.
Here's how we avoid ever having a double
anywhere:
var bd = new BigDecimal("12334555578912349.13");
System.out.println(bd);
In general if you want to provide meaningful guarantees about precision, if your code contains the word double
anywhere in it, you broke it. Do a quick search through the code for the word 'double' and until that search returns 0 hits, keep eliminating its use.
Alternatives that can provide guarantees about precision:
- BigDecimal, of course. Note that BD can't divide without specifying rules about how to round it (for the same reason 1/3 becomes 0.333333... never ends).
- Eliminate the fraction. For example, if that represents the GDP of a nation, store it as cents and not as euros, in a
long
and not adouble
. - If the thing doesn't represent a number that you ever intend to do any math on (for example, it's a social security number or an ISBN code or some such), store it as a String.