Perl再次舍入错误 [英] Perl rounding error again

查看:89
本文介绍了Perl再次舍入错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

显示问题的示例:

  • 电话号码为105;
  • 除以1000(结果为0.105)
  • 排在小数点后两位的应该是:0.11

现在,有几个脚本-基于对其他问题的答案:

Now, several scripts - based on answers to another questions:

这是大多数建议,大多数使用printf的解决方案.

This is mostly recommented and mostly upvoted solution is using printf.

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

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

but prints a wrong result. In the comment to https://stackoverflow.com/a/1838885 @Sinan Unur says (6 times upvoted comment):

也将sprintf(%.3f",$ value)用于数学目的.

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

但是,它有时"无法正常工作……如上所述.

but, it didn't works "sometimes"... like above.

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

The another recommented solution 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:

Wrong result too. Another recommened one 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 对此抱怨.

good result 0.11, however a comment here https://stackoverflow.com/a/571740 complains about it.

最后是我自己"功能的另一个建议:

and finally another recommendation "by my own" function:

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,但是不能证明它是正确的.

prints 0.11 too, but can't prove it's correctness.

供参考,我读到:

  • 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浮点数/ 是什么使这个问题非常好的总体看法.

and finally this too: http://www.exploringbinary.com/inconsistent-rounding-of-printed-floating-point-numbers/ what gives a an really good overall view to the problem.

我理解这不是所有语言的共同问题,但请毕竟 以上阅读-我仍然有这个问题:

I understand than it is common problem to all languages, but please, after all above reading - I still have this question:

在perl中将浮点数舍入为N的防错方法是什么 小数位-以数学上正确的方式,例如什么会舍入结果 正确地将105/1000精确到小数点后N位,而没有惊喜" ...

What is the error-proof way in perl to round a floating point number to N decimal places - with mathematically correct way, e.g. what will round results like 105/1000 correctly to N decimal places without "surprises"...

推荐答案

在古老的整数数学编程时代,我们习惯假装使用小数位:

In the old Integer math days of programming, we use to pretend to use decimal places:

N = 345
DISPLAY N        # Displays 345
DISPLAY (1.2) N  # Displays 3.45

当我们尝试正确地四舍五入营业税时,我们学到了一个宝贵的窍门:

We learned a valuable trick when attempting to round sales taxes correctly:

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.

By adding in 1/2 of the precision, I display the rounding correctly. When the number is 1.344, adding .005 made it 1.349, and chopping off the last digit displays dip lays 1.344. When I do the same thing with 1.345, adding in .005 makes it 1.350 and removing the last digit displays it as 1.35.

您可以使用一个子例程来执行此操作,该子例程将返回取整后的金额.

You could do this with a subroutine that will return the rounded amount.

有一个

There is a PerlFAQ on this subject. It recommends simply using printf to get the correct results:

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无效.但是:

For Pi, this works, but not for .105. However:

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警告我有关使用roundrounding作为将来可能的保留字的情况.

This looks like an issue with the way Perl stores .105 internally. Probably something like .10499999999 which would be correctly rounded downwards. I also noticed that Perl warns me about using round and rounding as possible future reserved words.

这篇关于Perl再次舍入错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆