我发现了一个但是在我的代码中,经过一些搜索,我意识到我正在执行的一些浮动操作产生了错误的结果。所以我输入了以下循环:
float f = 0f;
for(int i =0; i<15; i++){
f+= 10.1f;
System.out.println(f);
}
但是在结果中我得到了意想不到的额外小数值:
10.1
20.2
30.300001
40.4
50.5
60.6
70.7
80.799995
90.899994
100.99999
111.09999
121.19999
131.29999
141.4
151.5
这里发生了什么,我该如何预防?
答案 0 :(得分:3)
你不能“阻止”它。你需要做的是期待和补偿。
请参阅:Every Computer Scientist Should Know About Floating-Point Arithmetic
答案 1 :(得分:3)
数字存储为二进制,并且在一定精度下,二进制和十进制之间的表示不完美,实质上导致“舍入错误”。如果精度在这种情况下很重要,请尝试使用BigDecimal
答案 2 :(得分:1)
代码中的两个操作会导致错误:
10.1f
转换为float
。这种转换是不精确的,因为10.1无法用Java使用的浮点格式精确表示。10.1f
添加到先前的f
值。在许多这些添加中,精确的总和不能完全适合浮点格式,因此结果必须是四舍五入的。您可以修改循环以避免累积错误:
for (int i = 0; i < 15; i++)
{
f = (i+1) * 101 / 10.f;
System.out.println(f);
}
当您以这种方式编写代码时,f
在每次迭代中仍然不会完全是10.1•( i +1),但它将是最接近的可表示值。在这个新版本中,(i+1) * 101
的确切计算,10.f
正好是10,因为10可以浮点格式表示。这意味着唯一的错误是在除法运算中。该操作将返回最接近确切结果的可表示值。
Java使用IEEE-754二进制浮点,float
为32位,double
为64位。在这些格式中,数字基本上表示为2的幂的整数倍。在32位格式中,整数必须具有小于2 24 的幅度。在32位格式中,最接近10.1的是5295309•2 -19 ,即10.1000003814697265625。