Perl再次舍入错误 [英] Perl rounding error again
问题描述
显示问题的示例:
- 电话号码为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警告我有关使用round
和rounding
作为将来可能的保留字的情况.
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屋!