C ++如何避免浮点算术错误

时间:2013-02-13 17:55:27

标签: c++ floating-point floating-point-precision

我正在编写一个使用float递增的循环,但我遇到了以下示例中说明的浮点算术问题:

for(float value = -2.0; value <= 2.0; value += 0.2)
    std::cout << value << std::endl;

这是输出:

-2
-1.8
-1.6
-1.4
-1.2
-1
-0.8
-0.6
-0.4
-0.2
1.46031e-07
0.2
0.4
0.6
0.8
1
1.2
1.4
1.6
1.8

为什么我得到的是1.46031e-07而不是0?我知道这与浮点错误有关,但是我无法理解它为什么会发生以及我应该做些什么来防止这种情况发生(如果有办法)。有人可以解释(或指向我的链接),这将有助于我理解?任何输入都表示赞赏。谢谢!

6 个答案:

答案 0 :(得分:26)

正如其他人所说,这是由于实数是无限且无数的集合,而浮点表示使用有限数量的位。浮点数只能逼近实数,即使在很多简单的情况下由于它们的定义也不精确。正如您现在所看到的,0.2实际上不是0.2,而是一个非常接近它的数字。当您将这些添加到value时,您会在每一步累积错误。

作为替代方案,请尝试使用int进行迭代并将结果除以将其恢复到您需要的域中:

for (int value = -20; value <= 20; value += 2) {
  std::cout << (value / 10.f) << std::endl;
}

对我来说,这给了:

-2
-1.8
-1.6
-1.4
-1.2
-1
-0.8
-0.6
-0.4
-0.2
0
0.2
0.4
0.6
0.8
1
1.2
1.4
1.6
1.8
2

答案 1 :(得分:7)

这是因为浮点数只有一定的离散精度。

0.2实际上并不是0.2,而是在内部表示为略有不同的数字。

这就是你看到差异的原因。

这在所有浮点计算中都很常见,你真的无法避免它。

答案 2 :(得分:7)

没有明确的解决方案可以避免浮点精度损失。我建议您查看以下文件:What every computer scientist should know about floating point arithmetic

答案 3 :(得分:6)

让我们做你的循环,但提高输出精度。

<强>码

for(float value = -2.0; value <= 2.0; value += 0.2)
    std::cout << std::setprecision(100) << value << std::endl;

<强>输出:

-2
-1.7999999523162841796875
-1.599999904632568359375
-1.3999998569488525390625
-1.19999980926513671875
-0.999999821186065673828125
-0.79999983310699462890625
-0.599999845027923583984375
-0.3999998569488525390625
-0.19999985396862030029296875
1.460313825418779742904007434844970703125e-07
0.20000015199184417724609375
0.400000154972076416015625
0.6000001430511474609375
0.800000131130218505859375
1.00000011920928955078125
1.20000016689300537109375
1.40000021457672119140625
1.60000026226043701171875
1.80000030994415283203125

答案 4 :(得分:5)

使用整数并分频:

for(int value = -20; value <= 20; value += 2)
    std::cout << (value/10.0) << std::endl;

答案 5 :(得分:1)

通过一些算法书或使用互联网了解浮点表示。那里有很多资源。

当时,当你的东西非常接近于零时,你想要的东西似乎是某种方式来获得零。我们都知道我们称这个过程为“四舍五入”。 :)所以为什么不在打印这些数字时使用它。 printf函数为这些类型提供了良好的格式化功能。如果您不知道如何使用printf格式化,请检查以下链接中的表格。 (您可以使用格式化进行舍入并正确显示数字) printf ref:http://www.cplusplus.com/reference/cstdio/printf/?kw=printf

- 编辑 -

也许有些人知道,根据数学1.99999999 ......与2.0相同。唯一的区别是代表性。但数量是一样的。

您的浮点问题与此类似一点点。 (这只是为了您的澄清。您的问题与1.9999 ....不一样。)

相关问题