2

我正在使用 Perl 中的Statistics::Descriptive库来计算频率分布并遇到浮点舍入误差问题。

我将两个值 0.205 和 0.205(取自其他数字并 sprintf'd 到那些)传递给 stats 模块并要求它计算频率分布,但它陷入了无限循环。

使用调试器单步执行,我可以看到它正在执行以下操作:

my $interval = $self->{sample_range}/$partitions;

my $iter = $self->{min};

while (($iter += $interval) <  $self->{max}) {

  $bins{$iter} = 0;

  push @k, $iter;  ##Keep the "keys" unstringified

}

$self->sample_range (范围是 max-min)返回 2.77555756156289e-17 而不是我期望的 0。这意味着循环 ((min+=range) < max)) 进入(出于所有意图和目的)无限循环。

DB<8> 打印 $self->{max};
0.205
DB<9> 打印 $self->{min};
0.205
DB<10> 打印 $self->{max}-$self->{min};
2.77555756156289e-17

所以这看起来像一个舍入问题。不过,我想不出如何解决这个问题,而且我不确定编辑库是个好主意。我正在寻找解决方法或替代方法的建议。

干杯,尼尔

4

3 回答 3

5

我是 Statistics::Descriptive 维护者。由于其数字性质,已报告了许多舍入问题。我相信这个特定的版本在我最近发布的你使用的版本的更高版本中得到了修复,方法是使用乘法而不是 +=。

请使用CPAN的最新版本,应该会更好。

于 2009-06-03T15:47:29.573 回答
3

不完全是一个舍入问题;你可以看到更精确的值,比如

printf("%.18g %.18g", $self->{max}, $self->{min});

在我看来,模块中存在一个缺陷,它假设样本范围可以分成 $partitions 块;因为浮点没有无限精度,所以这并不总是可能的。在您的情况下,最小值和最大值是完全相邻的可表示值,因此不能有多个分区。我不知道该模块究竟将分区用于什么,所以我不确定这可能会产生什么影响。该模块中另一个可能的问题是它使用数字作为散列键,这隐含地对它们进行字符串化,从而稍微舍入值。

在将数据提供给模块之前,您可能会通过字符串化清洗数据取得一些成功:

$data = 0+"$data";

这至少将确保(使用默认打印精度)看起来相等的两个数字实际上是相等的。

于 2009-06-03T13:28:13.117 回答
-1

这不应该导致无限循环。$self->{sample_range}/$partitions如果为 0 ,会导致该循环无限的原因。

于 2009-06-03T13:32:22.907 回答