Object num = 12334555578912349.13;
System.out.println(BigDecimal.valueOf(((Number) num).doubleValue()).setScale(2, BigDecimal.ROUND_HALF_EVEN));
我期望该值为12334555578912349.13但是输出是123345555789123504.00
如何防止舍入?
Object num = 12334555578912349.13;
你已经输了。根据java规范,源文件中的字面文本'12334555578912349.13'被解释为双精度类型。考虑到计算机不是魔法,double
值是64位值,因此,最多只有2^64个数字可以用它表示。我们称这些数字为"幸运数字"。12334555578912349.13不是被祝福的数字之一。与此最接近的数字是123345555789123504.0,这就是该值"编译"到的值。一旦你到了123345555789123504.0,就没有回头路了。
那么解决方案就是永远不把'12334555578912349.13'作为你的源文件的文字,因为如果你这样做,你会立即失去游戏。
这是我们如何避免在任何地方使用double
的方法:
var bd = new BigDecimal("12334555578912349.13");
System.out.println(bd);
一般来说,如果你想提供有意义的精度保证,如果你的代码在任何地方包含double
这个词,你就破坏了它。在代码中快速搜索单词"double",直到搜索返回0个结果,继续消除它的使用。
可以提供精度保证的替代方法:
- 当然是BigDecimal。请注意,如果没有指定如何舍入的规则,BD就不能除法(出于同样的原因,1/3变成0.333333…永远不会结束)。
- 消去分数。例如,如果它代表一个国家的国内生产总值,将其存储为美分而不是欧元,在
long
而不是double
中。 - 如果这个东西不代表你打算做任何数学运算的数字(例如,它是一个社会安全号码或ISBN代码或诸如此类的),将其存储为String。