浮点表示如何从perl中的十进制表示中取消1?

时间:2009-11-17 16:16:30

标签: perl floating-point decimal

我在一些“humanize_bytes()”代码中遇到了一个有趣的问题。此循环表示没有所有其他逻辑的问题。当字节被截断为“人类可读”级别时,循环需要停止。它会一直迭代,直到最终值小于1024(或可指定的字节大小)。

当函数输出“1024.0 P”为1024 PB时,我开始研究这个问题。起初我以为我不小心使用了< = vs<,但经过进一步的检查,我发现发生了一些更有趣的事情。

此代码重现了该问题。我正在使用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,但浮动的是1024.这怎么可能?显然,perl使用十进制表示法。

2 个答案:

答案 0 :(得分:10)

您的原始值不是1024 PB,不到256。 (我注意到这一点,将其弹出到dc(1)并以十六进制打印:0xFFFFFFFFFFFFF00。)

因此,每次循环时你的数字都会比你预期的略有不同,最后它会略微变小。

如果你有更多的精确度,你最终会得到

1023.999999999999772626324556767940

这自然地截断为1023并且舍入为1024。

答案 1 :(得分:2)

Perl似乎将传递给%f的值四舍五入。如果您将值包装在int($final)中,则会得到1023输出,表明%d运算符正在执行正确的操作(始终向下舍入到最接近的整数)。

相关问题