这是一个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";
}
输出:
0.254 => 0.25
0.255 => 0.26
0.256 => 0.26
100.254 => 100.25
100.255 => 100.25
100.256 => 100.26
对我而言,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错误?如果它是理想的行为,为什么它会这样工作?
答案 0 :(得分:18)
如果你添加这一行:
$number = sprintf '%.15f', $number;
在打印之前,您将拥有:
0.254000000000000 => 0.25
0.255000000000000 => 0.26
0.256000000000000 => 0.26
100.254000000000005 => 100.25
100.254999999999995 => 100.25
100.256000000000000 => 100.26
正如您所看到的,100.255
并不完全是100.255
,这是由于浮点数的表示。
答案 1 :(得分:7)
Perl使用底层C库进行格式化。这个库的功能可能因平台而异。甚至POSIX都说"低阶数字应以实现定义的方式舍入。"
在glibc中,大多数perl二进制文件可以使用glibc,你看到的行为会受到以下几个方面的影响:
首先,正如另一个答案中所指出的,您认为正在舍入的值可能无法在浮点中精确表示,并且舍入的方式将取决于它是否是下一个更高或更低的可表示数字。< / p>
其次,即使该值在两次可能的舍入之间可以准确表示,glibc也会使用银行家的舍入。也就是说,它会四舍五入到偶数位。因此sprintf '%.1g', .25
将生成.2
,但sprintf '%.1g', .75
将生成.8
。
Perl Cookbook的引用是完全错误的。