我注意到Java浮点精度的一些问题
Float.parseFloat("0.0065") - 0.001 // 0.0055000000134110451
new Float("0.027") - 0.001 // 0.02600000000700354575
Float.valueOf("0.074") - 0.001 // 0.07399999999999999999
我不仅遇到Float
问题,还问Double
。
有人可以解释幕后发生的事情,我们怎样才能获得准确的数字?在处理这些问题时,处理这个问题的正确方法是什么?
答案 0 :(得分:29)
问题很简单float
具有有限的精度;它不能完全代表0.0065
。 (当然,double
也是如此:它具有更高的精度,但仍然是有限的。)
使上述问题更加明显的另一个问题是,0.001
是double
而不是float
,因此您的float
正在升级为double
执行减法操作,当然此时系统无法恢复double
所表示的缺失精度。要解决这个问题,你可以写:
float f = Float.parseFloat("0.0065") - 0.001f;
使用0.001f
代替0.001
。
答案 1 :(得分:6)
见What Every Computer Scientist Should Know About Floating-Point Arithmetic。你的结果对我来说是正确的。
如果您不喜欢浮点数的工作方式,请尝试使用BigDecimal之类的内容。
答案 2 :(得分:5)
你得到了正确的结果。完全没有这样的float
0.027,也没有这样的double
。如果您使用float
或double
,总是会收到这些错误。
float
和double
存储为二进制分数:类似于1/2 + 1/4 + 1/16 ......您无法获得所有小数要精确存储的值作为有限精度二进制分数。这在数学上是不可能的。
唯一的选择是使用BigDecimal
,您可以使用它来获取精确的小数值。
答案 3 :(得分:4)
来自Java Tutorials page on Primitive Data Types:
浮点字面值的类型为float,如果它以字母
F
或f
结尾;否则其类型为double,并且可以选择以字母D
或d
结尾。
所以我认为你的文字(0.001
)是双打的,你从浮动中减去双打。
请改为尝试:
System.out.println((0.0065F - 0.001D)); // 0.005500000134110451
System.out.println((0.0065F - 0.001F)); // 0.0055
......你会得到:
0.005500000134110451
0.0055
因此,为您的文字添加F
后缀,您应该会得到更好的结果:
Float.parseFloat("0.0065") - 0.001F
new Float("0.027") - 0.001F
Float.valueOf("0.074") - 0.001F
答案 4 :(得分:3)
我会将你的float转换为字符串,然后使用BigDecimal。
This链接很好地解释了
new BigDecimal(String.valueOf(yourDoubleValue));
不要使用BigDecimal双构造函数,因为你仍会遇到错误
答案 5 :(得分:1)
如果您需要任意精度,请使用BigDecimal,不要浮动或加倍。您将使用float看到各种这种性质的舍入问题。
另外要小心不要使用BigDecimal的float / double构造函数,因为它会有同样的问题。改为使用String构造函数。
答案 6 :(得分:1)
浮点数无法准确表示十进制数。如果您需要在Java中准确表示数字,则应使用java.math.BigDecimal类:
BigDecimal d = new BigDecimal("0.0065");