在Perl中使用POSIX ceil()的意外结果

she*_*ide 2 floating-point perl posix ceil

我不能为我的生活弄清楚为什么以下产生它的结果.

use POSIX;
my $g = 6.65;
my $t = $g * 4;
my $r = $t - $g;
my $n = $r / $g;
my $c = ceil($n);
print "$c ($n)\n";
Run Code Online (Sandbox Code Playgroud)

Sigil-tastic,我知道 - 抱歉.

我已经为我的应用解决了这个问题,如下所示:

use POSIX;
my $g = 6.65;
my $t = $g * 4;
my $r = $t - $g;
my $n = $r / $g;
my $c = ceil("$n");
print "$c ($n)\n";
Run Code Online (Sandbox Code Playgroud)

......但我很困惑为什么这里有必要.

Leo*_*ans 8

发生的事情是:在我的计算机上$n包含浮点值,因此不完全等于.Perl非常聪明,可以在打印时将其舍入,但是当您明确使用浮点函数时,它将完全按照它所宣传的内容进行:它到下一个整数:.33.000000000000000444093ceil4

这是使用浮点数的现实,绝不是Perl特定的.你不应该依赖他们的确切价值.


FMc*_*FMc 6

use strict;
use warnings;
use POSIX;

my $g = 6.65;
my $t = $g * 4;
my $r = $t - $g;
my $n = $r / $g;  # Should be exactly 3.

# But it's not.
print "Equals 3\n" if $n == 3;

# Check it more closely.
printf "%.18f\n", $n;

# So ceil() is doing the right thing after all.
my $c = ceil($n);
print "g=$g t=$t r=$r n=$n c=$c\n";
Run Code Online (Sandbox Code Playgroud)


Sin*_*nür 5

强硬的戈德堡参考:每个计算机科学家应该知道的关于浮点运算的内容.

使用Perl,在数字运算中将字符串视为数字的能力变成了一个优势,因为您可以轻松地使用它sprintf来明确指定所需的精度:

use strict; use warnings;

use POSIX qw( ceil );
my $g = 6.65;
my $t = $g * 4;
my $r = $t - $g;
my $n = $r / $g;
my $c = ceil( sprintf '%.6f', $n );
print "$c ($n)\n";
Run Code Online (Sandbox Code Playgroud)

输出:

C:\Temp> g
3 (3)

问题出现的原因是,由于可用于表示数字的有限位数,因此只有大量但有限数量的数字可以浮点表示.鉴于实线上有无数的数字,这将导致在存在中间操作时出现近似和舍入误差.