Perl for loop to haywire

Dev*_*WAH 5 perl for-loop

我在Perl中有一个简单的for循环

for ($i=0; $i <= 360; $i += 0.01)
{
print "$i ";
}
Run Code Online (Sandbox Code Playgroud)

为什么当我运行这段代码时,我得到以下输出,一旦达到0.81,它突然开始加载更多的小数位?我知道我可以简单地围绕以避免这个问题,但我想知道它为什么会发生.0.01的增量似乎并不疯狂.

 0.77
 0.78
 0.79
 0.8
 0.81
 0.820000000000001
 0.830000000000001
 0.840000000000001
 0.850000000000001
 0.860000000000001
 0.870000000000001
Run Code Online (Sandbox Code Playgroud)

Jen*_*rat 16

计算机使用二进制表示.并非所有十进制浮点数都具有二进制表示法的精确表示,因此可能会发生一些错误(实际上是一个舍入差异).这与您不应将浮点数用于货币值的原因相同:

弄乱了收件人http://img.thedailywtf.com/images/200902/errord/DSC00669.JPG

(图片来自dailywtf)

解决此问题的最优雅方法是使用整数进行计算,将它们分成正确的小数位数并使用sprintf限制打印的小数位数.这将确保:

  • 总是要打印出正确的结果
  • 舍入误差不会累积

试试这段代码:

#!/usr/bin/perl
for ($i=0; $i <= 360*100; $i += 1) {
  printf "%.2f \n", $i/100;
}
Run Code Online (Sandbox Code Playgroud)

  • +1是野外不正确的编程实践的文件证据! (8认同)

Jon*_*ler 7

基本上,因为十进制数0.01在二进制浮点中没有精确表示,所以随着时间的推移,将最佳近似值加到0.01会偏离您想要的答案.

这是(二进制)浮点运算的基本属性,而不是Perl特有的.每个计算机科学家应该知道的关于浮点算术是标准参考,你可以通过谷歌搜索很容易地找到它.

另请参阅:C编译器错误(浮点运算),毫无疑问是无数其他问题.


Kernighan&Plauger在他们古老但经典的书"编程风格的元素"中说:

  • 一位聪明的老程序员曾经说过"浮点数就像一堆沙子;每次移动一个,你就会失去一点沙子并获得一点污垢".

他们还说:

  • 10*0.1几乎不是1.0

两种说法都指出浮点运算不精确.

请注意,一些现代CPU(IBM PowerPC)内置了IEEE 754:2008十进制浮点运算.如果Perl使用了正确的类型(可能没有),那么你的计算就是精确的.


归档时间:

查看次数:

662 次

最近记录:

6 年,3 月 前