bes*_*bov 11 floating-point perl printf
这是一个perl脚本:
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
my @numbers = qw(
0.254
0.255
0.256
);
foreach my $number (@numbers) {
my $rounded = sprintf '%.2f', $number;
say "$number => $rounded";
}
foreach my $number (@numbers) {
$number += 100;
my $rounded = sprintf '%.2f', $number;
say "$number => $rounded";
}
Run Code Online (Sandbox Code Playgroud)
它输出:
0.254 => 0.25
0.255 => 0.26
0.256 => 0.26
100.254 => 100.25
100.255 => 100.25
100.256 => 100.26
Run Code Online (Sandbox Code Playgroud)
对我来说,Perl与舍入不一致是很奇怪的.我希望以.255结尾的两个数字都被舍入为.26这对于0.255是正确的,但对于数字100.255它是错误的
以下是Perl Cookbook的报价http://docstore.mik.ua/orelly/perl/cookbook/ch02_04.htm
sprintf.f格式允许您指定特定数量的小数位以将其参数舍入到.Perl查看下面的数字,如果它是5或更大,则向上舍入,否则向下舍入.
但我在http://perldoc.perl.org/functions/sprintf.html中看不到任何证据证明它是正确的
这是sprintf或Perl Cookbook中的错误吗?如果需要行为,为什么它会这样工作?
Tot*_*oto 18
如果你添加这一行:
$number = sprintf '%.15f', $number;
Run Code Online (Sandbox Code Playgroud)
在打印之前,您将拥有:
0.254000000000000 => 0.25
0.255000000000000 => 0.26
0.256000000000000 => 0.26
100.254000000000005 => 100.25
100.254999999999995 => 100.25
100.256000000000000 => 100.26
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,100.255
是不完全的100.255
,这是由于浮点数的表示.
Perl使用底层C库进行格式化.这个库的功能可能因平台而异.甚至POSIX也说"低阶数字应以实现定义的方式进行舍入."
在glibc中,可以说大多数perl二进制文件都使用它,你看到的行为会受到以下几点的影响:
首先,正如另一个答案中所指出的,您认为正在舍入的值可能无法在浮点中精确表示,并且舍入的方式将取决于它是否是下一个更高或更低的可表示数字.
其次,即使价值在两次可能的舍入之间完全可以表示,glibc也会使用银行家的舍入.也就是说,它会四舍五入到偶数位.所以sprintf '%.1g', .25
会产生.2
,但sprintf '%.1g', .75
会产生.8
.
Perl Cookbook的引用是完全错误的.