Perl舍入错误再次出现

显示问题的示例:

>有一个数字105;
>除以1000(结果0.105)
>粗略到2位小数应为:0.11

现在,几个脚本 – 基于另一个问题的答案:

这大多是推荐的,并且大多数是使用printf的upVoted解决方案.

use 5.014;
use warnings;
my $i = 105;
printf "%.2f\n",$i/1000;   #prints 0.10

但打印错误的结果.在评论
https://stackoverflow.com/a/1838885 @Sinan Unur说(6次评论):

Use sprintf(“%.3f”,$value) for mathematical purposes too.

但是,它“有时”不起作用……就像上面一样.

一个推荐的解决方案Math :: BigFloat:

use 5.014;
use warnings;
use Math::BigFloat;
my $i = 105;

Math::BigFloat->precision(-2);
my $r = Math::BigFloat->new($i/1000);

say "$r";   #0.10 ;(

错误的结果也是如此.另一个推荐了一个bignum:

use 5.014;
use warnings;
use bignum ( p => -2 );
my $i = 105;
my $r = $i/1000;
say "$r";   #0.10 ;(

又错了. (

现在工作的人:

use 5.014;
use warnings;
use Math::Round;
my $i = 105;
say nearest(0.01,$i/1000); #GREAT prints 0.11 :)

好结果0.11,但是在这里发表评论https://stackoverflow.com/a/571740
抱怨它.

最后另一个推荐“我自己的”功能

use 5.014;
use warnings;
my $i = 105;
my $f = $i/1000;

say myround($f,2);  # 0.11

sub myround {
    my($float,$prec) = @_;
    my $f = $float * (10**$prec);
    my $r = int($f + $f/abs($f*2));
    return $r/(10**$prec);
}

也打印0.11,但无法证明它的正确性.

作为参考,我读到:

> How do you round a floating point number in Perl?
> In Perl,how can I limit the number of places after the decimal point but have no trailing zeroes?
> How do I set the floating point precision in Perl?
>和许多其他人……
>最后这也是:
http://www.exploringbinary.com/inconsistent-rounding-of-printed-floating-point-numbers/
什么给这个问题提供了一个非常好的整体观点.

我明白这是所有语言的常见问题,但毕竟请
以上阅读 – 我还有这个问题:

在perl中将浮点数舍入为N的错误方法是什么?
小数位 – 用数学上正确的方式,例如会有什么结果
像105/1000正确到N个小数位没有“惊喜”……

解决方法

在编程的旧整数数学时代,我们假装使用小数位:
N = 345
disPLAY N        # displays 345
disPLAY (1.2) N  # displays 3.45

在尝试正确计算销售税时,我们学到了一个有价值的技巧:

my $amount = 1.344;
my $amount_rounded = sprintf "%.2f",$amount + .005;
my $amount2 = 1.345;
my $amount_rounded2 = sprintf "%.2f",$amount2 + .005;
say "$amount_rounted   $amount_rounded2";  # prints 1.34 and 1.35

通过加上1/2的精度,我正确显示圆角.当数字为1.344时,添加.005使其成为1.349,并且切掉最后一位数字显示倾斜位于1.344.当我使用1.345执行相同的操作时,添加.005使其为1.350并删除最后一位数字将其显示为1.35.

您可以使用将返回舍入金额的子例程来执行此操作.

有趣…

这个主题一个PerlFAQ.它建议只使用printf来获得正确的结果:

use strict;
use warnings;
use feature qw(say);

my $number = .105;
say "$number";
printf "%.2f\n",$number;   # Prints .10 which is incorrect
printf "%.2f\n",3.1459;    # Prins 3.15 which is correct

对于Pi,这可行,但不适用于.105.然而:

use strict;
use warnings;
use feature qw(say);

my $number = .1051;
say "$number";
printf "%.2f\n",$number;   # Prints .11 which is correct
printf "%.2f\n",3.1459;    # Prints 3.15 which is correct

这看起来像是Perl在内部存储.105的方式的问题.可能类似于.10499999999,它可以正确向下舍入.我还注意到Perl警告我使用舍入和舍入作为可能的未来保留字.

相关文章

1. 如何去重 #!/usr/bin/perl use strict; my %hash; while(...
最近写了一个perl脚本,实现的功能是将表格中其中两列的数据...
表的数据字典格式如下:如果手动写MySQL建表语句,确认麻烦,...
巡检类工作经常会出具日报,最近在原有日报的基础上又新增了...
在实际生产环境中,常常需要从后台日志中截取报文,报文的形...
最近写的一个perl程序,通过关键词匹配统计其出现的频率,让...