为什么不能用浮点型表示金额?

3,297 阅读2分钟

参考博客:blog.csdn.net/bruce128/ar…

在java中,一般来说,我们的单精度float和双精度double已经可以满足我们的大部分需求了。但是不管是float和double都会出现浮点的误差,而这点误差在一般情况下并不影响我们的使用。

但是,在金融行业,一个小小的精度误差,可能会导致成千上万的损失,甚至严重点来说,可能会有牢狱之灾。因此,我们必须去严格的计算每一个小数点的值,不能出现任何误差。

也因此,出现了我们现在的这个问题,为什么不能用float和double等等等的浮点型来表示金额?

看代码:

结果为:

可以看出,随着运算数量的上升,明显看到误差的产生。这是float类型的运算,如果是double类型的话,那么误差将会更大。

这是第一个原因,使用float和double会出现误差,这在金融行业基本上不被允许的。

那么,仅仅是这个原因吗?

还有一个原因,我们要向float和double这两个基础数据类型中找寻。

这个问题和float和double在java中规定的数据长度有关。32位的浮点数float由3部分组成:1比特的符号位,8比特的阶码(exponent,指数),23比特的尾数(Mantissa,尾数)。这个结构会表示成一个小数点左边为1,以底数为2的科学计数法表示的二进制小数。浮点数的能表示的数据大小范围由阶码决定,但是能够表示的精度完全取决于尾数的长度。而64位的浮点数double是1比特的符号位,11比特的阶码(exponent,指数),52比特的尾数(Mantissa,尾数)。

于是,就会出现如下代码的情况:

结果为:
原因:

long的最大值是2的64次方减1,需要63个二进制位表示,即便是double,52位的尾数也无法完整的表示long的最大值。不能表示的部分也就只能被舍去了。所以导致了添加了10亿次之后,数值依然没有变化,因为添加的数值都被舍去了。

那么,应该怎么办呢?

JDK提供了一个BigDecimal的类,这个类可以表示任意精度的数字。