我有以下perl代码,想要使用sprintf的最后一个diget,但是当最后一个摘要为5时,我得到一些奇怪的结果我希望舍入为止,但实际结果与示例不同:
my $x = sprintf("%.1f",4.35); -> expected 4.4
my $y= sprintf("%.1f",4.36); -> expected 4.4
my $z = sprintf("%.1f",4.32); -> expected 4.3
print $x,"\n"; -> actual result 4.3 -> expected 4.4
print $y,"\n"; -> actual result 4.4 -> ok
print $z,"\n"; -> actual result 4.3 ->ok
如何更改上述代码/或者是否有其他选项可以获得预期结果?
答案 0 :(得分:5)
4.35将四舍五入为4.4,但实际上你的东西略低于4.35。
35/100是二进制周期性的,就像1/3是十进制周期一样。
$ perl -E'say sprintf "%.20g", 0.35'
0.34999999999999998
当然,这同样适用于4 35/100。
$ perl -E'say sprintf "%.20g", 4.35'
4.3499999999999996
因此,无法使用浮点数精确表示0.35和4.35。
以下解决方案依赖于0.5不是二进制周期性的事实(0.5 = 1/2 = 2 -1 ,幂的有限和为2):
$ perl -E'
say sprintf("%.0f", sprintf("%.15g", $_ * 10)) / 10
for 4.35, 4.36, 4.32;
'
4.4
4.4
4.3
答案 1 :(得分:2)
% perl -E 'printf("%.1f\n", $_) for ( 4.35, 4.350000001 )'
4.3
4.4
4.35
实际上是4.34999999999999999
kludge可能是:
% perl -E 'printf("%.1f\n", $_ + 1e-15) for ( 4.35, 4.350000001 )'
4.4
4.4
答案 2 :(得分:0)
最好的方法是不使用浮点数,而是在这里乘以10;特别是如果有钱的话。
对于不精确的计算,人们可能会接受4.35实际上是4.349999。
答案 3 :(得分:0)
尝试Math::Round模块,看看是否适合您的需求。
use Math::Round qw( nlowmult nhimult );
print nhimult(.1, 4.35), "\n"; # 4.4
print nhimult(.1, 4.45), "\n"; # 4.5
print nlowmult(.1, 4.35), "\n"; # 4.3
print nlowmult(.1, 4.45), "\n"; # 4.4