Java普通类型计算出错的问题

问题的产生

今天同学问了我一个问题,给了一段代码,问运行结果:
Java普通类型计算出错的问题
第一眼看上去感觉就是0.8啊,没毛病,可是要是这么简单的题怎么会问我呢,感觉是个陷阱啊,这时候想起来,浮点数的存储不是精确的,但是依然得不出答案,于是上IDE编译运行了一遍。
Java普通类型计算出错的问题
结果:0.79999995
其实不只是减法,加法也可能发生这种情况,可以参考 这里。是不是很奇怪呢,让我们一起去探索究竟。

原因

浮点数在内存中是按照IEEE754标准进行存储的,详细的介绍请Google或者百度,或者参考这篇文章 得到浮点数的二进制
原因就是计算机内部是通过二进制也就是0和1来存储数据的,浮点数也不例外,但是有些浮点数是无法精确存储的,看了上面那篇文章应该可以理解,只有由2的幂组成的数才可以精确存储。

2.0f在内存中可以准确的存储,这是2.0f的二进制存储图:
Java普通类型计算出错的问题

1.2f就无法精确的存储:
Java普通类型计算出错的问题

经过换算可以得到1.2f在内存中存储的其实是 1.2000000476837158203125E0
这里就可以体现出浮点数是在一定精度内还是准确的。

因为1.2f后面还有很多多余的数字,进行减法就相当于计算:
2.0 - 1.2000000476837158203125E0
它的结果就是0.7999999523162842
进行保留后就得到了我们输出的结果0.79999995

如何解决

通过java.math包中提供的BigDecimal类可以解决此类问题。
Java普通类型计算出错的问题

也一定要使用BigDecimal类中参数类型为String的构造函数
Java普通类型计算出错的问题

不然还是的不到正确的结果:
Java普通类型计算出错的问题

这是因为以String为参数的构造函数内部是采用字符串处理的,而以浮点数为参数,内部还是通过double类型实现,所以还是会出现精度损失的问题。

使用Java的到浮点数的二进制

得到浮点数的二进制这篇文章是使用C语言得到浮点数的二进制,使用java比C语言要简单,因为有方法可以调用。

可以使用Float类的静态方法floatToIntBits()或者floatToRawIntBits():
Java普通类型计算出错的问题

floatToIntBits()和floatToRawIntBits()的区别就在于当参数是NaN,floatToRawIntBits 不压缩所有将 NaN 编码为一个“规范”NaN 值的位模式。
Java普通类型计算出错的问题