使用sprintf来舍入浮点数

时间:2014-01-12 21:57:58

标签: perl

我有以下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

如何更改上述代码/或者是否有其他选项可以获得预期结果?

4 个答案:

答案 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