1

我有一个 for 循环,我想每次将变量增加 0.1,但是值的变化与增量不同,我不确定为什么。

我已经简化了 for 循环,但它仍然给出了一个奇怪的输出:

for (my $t = 1000; $t < 1500 ;$t+=0.1) {
print "$t\n";
}

它打印:

1034.9
1035
1035.1
1035.2
1035.3
1035.4
1035.49999999999
1035.59999999999
1035.69999999999
1035.79999999999
1035.89999999999
1035.99999999999
1036.09999999999
1036.19999999999
1036.29999999999
[it then goes on like this to 1500]

我不知道小数位是从哪里来的。这是我对 Perl 理解的问题吗?

提前致谢。

4

4 回答 4

9

1/10 是二进制的周期数,就像 1/3 是十进制的一样。它不能精确地表示为浮点数。

$ perl -e'printf "%.20g\n", 0.1'
0.10000000000000001

永远不要在没有容差的情况下将一个浮点数与另一个进行比较,并且要小心错误的累积。

这里使用整数进行算术运算并在需要时生成浮点数的简单解决方案

for (my $tx10 = 10000; $tx10 < 15000; ++$tx10) {
   my $t = $tx10/10;
   print "$t\n";
}

这简化为

for my $tx10 (10000..14999) {
   my $t = $tx10/10;
   print "$t\n";
}

         ____            ____             ____
0.1 = 0.00011    0.4 = 0.0110    0.7 = 0.10110
        ____                              ____
0.2 = 0.0011     0.5 = 0.1       0.8 = 0.11001
         ____            ____             ____
0.3 = 0.01001    0.6 = 0.1001    0.9 = 0.11100
于 2013-10-29T18:43:45.953 回答
2
for (my $t = 1000; $t < 1500 ;$t+=.1) {
    printf("%.1f\n", $t);
}
于 2013-10-29T18:25:40.150 回答
1

选择:

for (10000..14999) {
  my $t = $_/10;
  print "$t\n";
}

由于 0.1 不能以二进制精确指定,舍入误差会在您的代码中累积。在这个答案中,数量总是保持足够接近精确,以便 perl 的内部数字到字符串舍入将显示正确的数字。教训:尽可能使用整数。

于 2013-10-29T18:22:39.747 回答
0

测试条件

perl -le 'for (my $t = 1000.0; $t < 1500.0 ;$t+=0.1) {  print $t}'| perl -n -e '($a)=/(\d$)/; print "fail $a $b $_" if ($a eq $b); $b=$a'

另一种解决方法

perl -le 'for (my $t = 1000.0; $t < 1500.0 ;$t+=0.1) { $t=sprintf("%.1f", $t); print $t}'| perl -n -e '($a)=/(\d$)/; print "fail $a $b $_" if ($a eq $b); $b=$a'
于 2013-10-29T18:31:07.953 回答