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

问题描述:

可能重复:
Why is floating point arithmetic in C# imprecise?
Why does ghci say that 1.1 + 1.1 + 1.1 > 3.3 is True?为什么我在Perl中从自身中减去相同的浮点数时得不到零?

#!/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\n"; 

令人惊讶的输出最终是

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

难道不应该是零???? 请问任何人都可以这样解释......

+2

什么,你不觉得0.000000000000201655014354845是接近零? – Ether 2010-01-17 17:50:38

+0

这个问题并不完全是引用的非perl问题的重复,因为问题很复杂,因为perl提供的默认字符串化精度略低于可用的数字精度。 – ysth 2010-01-18 06:39:24

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

为什么它应该是零? 0.579787!= 0.579788和0.433273!= 0.433272。很可能没有一个具有精确的浮点表示,因此您应该期望一些不准确的地方。

+0

+1为太阳链接 – zedoo 2010-01-17 13:03:56

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

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

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

perlfaq4的答案Why am I getting long decimals (eg, 19.9499999999999) instead of the numbers I should be getting (eg, 19.95)?


内部,您的计算机代表浮点二进制数。数字(如两个幂)计算机不能完全存储所有数字。一些实际数字在这个过程中失去了精确性这是计算机如何存储数字并影响所有计算机语言的问题,而不仅仅是Perl。

perlnumber显示数字表示和转换的血淋淋的细节。

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

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

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

这是perlfaq的另一面;看到我对这个问题的评论。 – ysth 2010-01-18 06:43:33