Perl 添加一个浮点数数组会产生向前与向后相加的奇怪总和

Perl 添加一个浮点数数组会产生向前与向后相加的奇怪总和,perl,floating-point,Perl,Floating Point,我在perl中添加了求和和和浮点数组,并试图加快速度。当我尝试时,我开始得到奇怪的结果 #!/usr/bin/perl my $total = 0; my $sum = 0; # Compute $sum (adds from index 0 forward) my @y = @{$$self{"closing"}}[-$periods..-1]; my @x = map {${$_}{$what}} @y; # map { $sum += $_ } @x; $sum += $_ for @

我在perl中添加了求和和和浮点数组,并试图加快速度。当我尝试时,我开始得到奇怪的结果

#!/usr/bin/perl

my $total = 0;
my $sum = 0;

# Compute $sum (adds from index 0 forward)
my @y = @{$$self{"closing"}}[-$periods..-1];
my @x = map {${$_}{$what}} @y;
# map { $sum += $_ } @x;
$sum += $_ for @x;

# Compute $total (adds from index -1 backward)

for (my $i = -1; $i >= -$periods; $i--) {
    $total += ${${$$self{"closing"}}[$i]}{$what};
}

if($total != $sum) {
    printf("SMA($what, $periods) total ($total) != sum ($sum) %g\n",
       ($total - $sum));
}

# Example output:
#    SMA(close, 20) total (941.03) != sum (941.03) -2.27374e-13
当我计算$sum和$total时,我似乎得到了不同的答案

我唯一能想到的是,一个方法通过数组向前添加,另一个方法向后添加

这会导致它们以不同的方式溢出吗?我希望如此,但我从未想到我会得到不同的答案。请注意,差异很小-2.27374e-13

这是怎么回事,还是我的代码被破坏了


这是perl 5,版本16,subversion 3 v5.16.3,为x86_64-linux-thread-multi构建,正如Eric在评论中提到的那样,浮点运算是不关联的;因此,您执行操作的顺序将影响答案

虽然先添加较小的值是一个很好的建议,但重要的是要强调,即使只有常规的较小值,也可能存在差异。这里有一个例子:

  x  =  1.004028
  y  = 3.0039678
  z  =  4.000855
如果将其视为IEEE-754单精度浮点,即32位二进制格式,则我们得到:

  x + (y+z) = 8.008851
  (x+y) + z = 8.00885
无限精确的结果是8.0088508。所以两者都不是很好!对于科学计算来说,误差并不是微不足道的,而是不断累积的


这是一个丰富的领域,有许多数值算法来确保精度。虽然您选择哪一种完全取决于您的问题领域、特定需求和可用资源,但最著名的算法之一是Kahan的求和算法,请参见:。你可以很容易地将它应用到你的问题中,希望得到更好的结果。

map{$sum+=$\}@x最好写为@x的$sum+=$。您不应该将map用作循环,它用于将一个列表转换为另一个列表。已修复。它没有更改数学。浮点运算不关联。在其他方面中,如果首先累积大值,则没有足够的精度来精确地添加小值。但如果你先加上小数值,它们就可以准确地相加,然后再加上大数值。@DaveCross,我很感激!这就是我想做的。地图的事太草率了。非常接近的问题: