对浮点值或双精度值执行重复加法会产生意外结果



我在代码中发现了一个but,经过一番搜索,我意识到我正在执行的一些浮动操作产生了错误的结果。所以我输入了以下循环:

 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

这里发生了什么?我该如何预防?

你不能"阻止"它。你需要做的是期望它并进行补偿。

请参阅:每一位计算机科学家都应该知道的浮点运算

数字以二进制形式存储,在一定精度下,二进制和十进制之间的表示并不完美,本质上会导致"舍入误差"。如果在这种情况下精度很重要,请尝试使用BigDecimal而不是

代码中的两个操作会导致错误:

  • 源文本10.1ffloat的转换。这种转换是不精确的,因为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位格式中,整数的大小必须小于224。在32位格式中,最接近10.1的是5295309•2-19,即10.1000003814697265625。

相关内容

  • 没有找到相关文章

最新更新