【发布时间】:2014-08-21 00:11:11
【问题描述】:
显示问题的示例:
- 编号为 105;
- 除以 1000(结果 0.105)
- 小数点后两位应该是:0.11
现在,几个脚本 - 基于对另一个问题的回答:
这主要是推荐和大多数赞成的解决方案是使用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 次点赞评论):
也可以将 sprintf("%.3f", $value) 用于数学目的。
但是,它“有时”不起作用......就像上面一样。
另一个推荐的解决方案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?
还有很多很多其他...
最后也是这样: http://www.exploringbinary.com/inconsistent-rounding-of-printed-floating-point-numbers/ 是什么让您对问题有一个非常好的整体看法。
我明白这是所有语言的共同问题,但毕竟请 以上阅读 - 我仍然有这个问题:
perl 中将浮点数舍入为 N 的 防错 方法是什么
小数位 - 以数学上正确的方式,例如什么将四舍五入结果
像 105/1000 一样正确到 N 位小数,没有“惊喜”...
【问题讨论】:
-
就我个人而言,我总是依赖像 Pg/Oracle 这样的数据库来进行这种类型的计算。
-
我应该指出,在您的 Math::Bigfloat 解决方案中,您将一个公共浮点数传递给了 new(),这意味着解决您的问题为时已晚。您可能应该从(除法前)整数中制作一个 Bigfloat,以便让 Bigfloat 的除法方法为您提供可以使用的东西。
-
+1 表示 tjd 的评论。我会认为(很高兴被证明是错误的)如果您正确使用 Math::Bigfloat,它将是防错的
-
除了存储可以用 n/2^m 表示的数字,或者对那些内部状态始终为可以用 n/2^m 表示,以及结果。否则,错误是存储格式固有的。
标签: perl