在java语言中,对于要求精确的计算,都推荐使用诸如BigDecimal这样的工具类来处理,而不是用float或double来直接计算,这是因为单精度浮点数和双精度浮点数在计算过程中可能会出现误差,这在商业或军事项目是要绝对避免的!
今天我们不讨论为什么BigDecimal可以实现精确计算,我们讲一下,为什么会出现误差。
先说结论:不是所有十进制数都有相等的二进制形式(整数没有问题,问题出现在小数部份)
我们在写程序时,使用的通常都是十进制数,譬如,float price=2.2f;好,这个数字正常人都懂,但是机智的计算机却完全不明白,因为它只能识别1,0这两个数字。当要把2.2f转换成double时,误差就出现了,这又是为什么呢?2.2f在计算机中会以单精度小数的格式保存下来,那么问题来了,计算机能将2.2等值的转换成二进制形式吗?答案是:no!计算机只能保存一个与2.2非常接近的一个数。
2.2的二进制形式:10.00110011001100110011001100110011001100110011........一个无限循环的形式。计算机的存储空间是有限的,按单精度浮点数,只能存储24位尾数位,于是在计算机中保存的样子就是:
符号位 指数位 尾数
0 0000 0001 00011001100110011001100
为了方便统一使用原码。
而10.0011001100110011001100对应的十进制数是个啥有兴趣的自己算,反正不是2.2。那么由它转换成double类型,自然也不能得到准确的2.2的值了。
所以说数据误差的问题,与进制转换、数据存储都是有密切关系的。