Как можно обойти ошибку округления, которая вызывает бесконечный цикл в Perl's Statistics :: Descriptive? - PullRequest
2 голосов
/ 03 июня 2009

Я использую библиотеку Statistics :: Descriptive в Perl для вычисления частотных распределений и решения проблемы ошибки округления с плавающей запятой.

Я передаю два значения, 0.205 и 0.205 (взятые из других чисел и sprintf'd для них) в модуль статистики и прошу его рассчитать распределение частоты, но он застревает в бесконечном цикле.

Проходя через отладчик, я вижу, что он делает:

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)

DB <8> print $ self -> {max};
0,205
DB <9> print $ self -> {min};
0,205
DB <10> print $ self -> {max} - $ self -> {min};
2.77555756156289e-17

Так что это похоже на проблему округления. Я не могу думать, как исправить это на моей стороне, хотя, и я не уверен, что редактирование библиотеки - хорошая идея. Я ищу предложения об обходном пути или альтернативе.

Cheers, Neil

Ответы [ 3 ]

5 голосов
/ 03 июня 2009

Я статистика :: Описательный сопровождающий. Из-за его числового характера было зарегистрировано много проблем округления. Я полагаю, что эта конкретная версия была исправлена ​​в более поздней версии той, которую вы использовали, которую я недавно выпустил, используя умножение для делений вместо + =.

Пожалуйста, используйте самую последнюю версию от CPAN, и она должна быть лучше.

3 голосов
/ 03 июня 2009

Не совсем проблема округления; вы можете увидеть более точные значения, например,

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

Похоже, в модуле есть недостаток, в котором предполагается, что диапазон выборки можно разделить на части $ partitions; поскольку плавающая точка не имеет бесконечной точности, это не всегда возможно. В вашем случае значения min и max являются точно смежными представляемыми значениями, поэтому не может быть более одного раздела. Я не знаю, для чего именно модуль использует разделы, поэтому я не уверен, какое это может быть влияние. Другая возможная проблема в модуле состоит в том, что он использует числа в качестве хеш-ключей, что неявно строковые их, что немного округляет значение.

У вас могут быть некоторые успехи в отмывании ваших данных посредством строкового форматирования перед их подачей к модулю:

$data = 0+"$data";

Это как минимум гарантирует, что два числа, которые (с точностью печати по умолчанию) кажутся равными, на самом деле равны.

0 голосов
/ 03 июня 2009

Это не должно вызывать бесконечный цикл. То, что заставило бы этот цикл быть бесконечным, было бы, если $self->{sample_range}/$partitions равно 0.

...