Как представление с плавающей запятой может быть не равно 1 десятичному представлению в perl? - PullRequest
1 голос
/ 17 ноября 2009

Я столкнулся с интересной проблемой в моем коде "humanize_bytes ()". Этот цикл представляет проблему без всякой другой логики. Цикл должен быть остановлен, когда байты были усечены до «читабельного» уровня. Итерация продолжается до тех пор, пока окончательное значение не станет меньше 1024 (или не может быть указан байт).

Я начал изучать проблему, когда функция выдает «1024.0 P» для 1024 петабайт. Сначала я подумал, что случайно использую <= vs <, но при дальнейшей проверке я обнаружил, что происходит нечто более интересное. </p>

Этот код воспроизводит проблему. Я использую Perl 5.8.8.

use strict;

my $bytesize = 1024;
my $final = 1152921504606846720;
while (1) {
    printf "bytesize %%d: %d %%f: %s %s final %%d: %19d %%f: %26f\n",
        $bytesize,$bytesize,
        (
            $bytesize == $final ? '==' :
            $bytesize > $final  ? '>'  :
            $bytesize < $final  ? '<'  :
            '<error>'
        ),
        $final,$final;
    last if $final < $bytesize;
    $final /= $bytesize;
}
printf "final = bytesize d:%d f:%s %s final d:%d f:%f\n",
    $bytesize,$bytesize,
    (
        $bytesize == $final ? '==' :
        $bytesize > $final  ? '>'  :
        $bytesize < $final  ? '<'  :
        '<error>'
    ),
    $final,$final;

Вывод, который я получаю:

bytesize %d: 1024 %f: 1024 < final %d: 1152921504606846720 %f: 1152921504606846720.000000
bytesize %d: 1024 %f: 1024 < final %d:    1125899906842623 %f:    1125899906842623.750000
bytesize %d: 1024 %f: 1024 < final %d:       1099511627775 %f:       1099511627775.999756
bytesize %d: 1024 %f: 1024 < final %d:          1073741823 %f:          1073741824.000000
bytesize %d: 1024 %f: 1024 < final %d:             1048575 %f:             1048576.000000
bytesize %d: 1024 %f: 1024 > final %d:                1023 %f:                1024.000000
final = bytesize d:1024 f:1024 > final d:1023 f:1024.000000

Здесь следует отметить, что конечное значение в десятичном виде - 1023, а в float - 1024. Как это может быть? И, очевидно, Perl использует десятичное представление.

Ответы [ 2 ]

10 голосов
/ 17 ноября 2009

Ваше исходное значение не 1024 петабайта, оно на 256 меньше. (Я заметил это, вставив его в dc (1) и напечатав в шестнадцатеричном виде: 0xFFFFFFFFFFFFF00.)

Следовательно, каждый раз, когда вы проходите через цикл, ваше число немного отличается от ожидаемого, и, в конце концов, оно немного меньше.

Если бы у вас было больше точности, вы бы получили

1023,999999999999772626324556767940

Это естественно усекает до 1023 и округляет до 1024.

2 голосов
/ 17 ноября 2009

Perl, кажется, округляет значение, переданное %f. Если вы введете значение в int($final), вы получите вывод 1023, указывающий, что оператор %d делает правильные вещи (всегда округляя до ближайшего целого числа).

...