当我在Perl中从自身中减去相同的浮点数时,为什么不能得到零?

Why don't I get zero when I subtract the same floating point number from itself in Perl?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicates:
Why is floating point arithmetic in C# imprecise?
Why does ghci say that 1.1 + 1.1 + 1.1 > 3.3 is True?

1
2
3
4
5
6
7
8
#!/usr/bin/perl
$l1 ="0+0.590580+0.583742+0.579787+0.564928+0.504538+0.459805+0.433273+0.384211+0.3035810";
$l2 ="0+0.590580+0.583742+0.579788+0.564928+0.504538+0.459805+0.433272+0.384211+0.3035810";
$val1 = eval ($l1);
$val2 = eval ($l2);
$diff = (($val1 - $val2)/$val1)*100;
print" (($val1 - $val2)/$val1)*100 ==> $diff
"
;

令人惊讶的是,最终的产出是

1
((4.404445 - 4.404445)/4.404445)*100 ==> -2.01655014354845e-14.

它不应该是零吗?????请任何人解释一下……


每一个计算机科学家都应该知道什么是浮点运算

明白为什么C中的浮点运算不精确吗?

这与Perl无关,但与浮点相关。


它非常接近于零,这是我所期望的。

为什么应该是零?0.579787!=0.579788和0.433273!= 0.433272。很可能这些都没有一个精确的浮点表示,所以您应该期待一些不准确的地方。


从Perlfaq4的答案到为什么我会得到长小数(如19.94999999999),而不是我应该得到的数字(如19.95)?:

在内部,您的计算机以二进制表示浮点数字。数字计算机(如二次乘方)不能准确地存储所有的数字。有些实数在这个过程中会失去精度。这是计算机如何存储数字和影响所有计算机语言的问题,而不仅仅是Perl。

PerlNumber显示数字表示和转换的详细信息。

要限制数字中的小数位数,可以使用printf或sprintf函数。有关详细信息,请参阅"浮点运算"。

1
2
3
printf"%.2f", 10/3;

my $number = sprintf"%.2f", 10/3;


当您将两个字符串更改为相等时($l1$l2之间有两个不同的数字),它确实会导致零。

它所证明的是,您可以创建两个不同的浮点数($val1$val2,它们在打印时看起来相同,但在内部却有微小的差别。如果你不小心的话,这些差异可以放大。

Vinko Vrsalovic发布了一些很好的链接来解释原因。