我有这个代码:
sub range {
my ($start, $end, $step) = @_;
if($step == 0) {
die("Step size cannot be 0!")
}
if($start > $end) {
($start, $end) = ($end, $start);
}
my @range = ();
for (my $i = $start; $i <= $end; $i += $step) {
push @range, $i;
}
return @range;
}
运行时
my @range = range(-3, -2.7, 0.01);
我得到这个列表:
...
$VAR23 = '-2.78';
$VAR24 = '-2.77';
$VAR25 = '-2.76000000000001';
$VAR26 = '-2.75000000000001';
$VAR27 = '-2.74000000000001';
$VAR28 = '-2.73000000000001';
$VAR29 = '-2.72000000000001';
$VAR30 = '-2.71000000000001';
$VAR31 = '-2.70000000000001';
为什么会这样?
我在 4.9.0-7-amd64 #1 SMP Debian 4.9.107-1 机器上有 perl v5.24.1。添加 bignum 模块不会改变计算的变量错误的事实。
此外,在执行诸如"-2.7 - 0.01"之类的操作时,不会发生这种情况。
为什么会这样?
了解每个程序员应该了解的浮点运算知识。
添加 bignum 模块不会改变计算的变量错误的事实。
我猜你在sub range
中添加了use bignum;
,但由于bignum
是作用域的,这不会自动影响传递到该sub
的变量。因此,要么bignum
需要在定义您传递到range
的文本的任何地方有效并且它将起作用,或者,您可以升级sub
本身中的变量,如下所示:
use Math::BigRat;
sub range {
my $start = Math::BigRat->new(shift);
my $end = Math::BigRat->new(shift);
my $step = Math::BigRat->new(shift);
...
return map {$_->numify} @range;
}
但是,在任何地方使用Math::BigRat
、Math::BigFloat
等(包括通过bignum
和相关编译指示(对象都会减慢代码速度,因此这可能是矫枉过正。为了使对象仅在上述sub
中使用,我将对象降级回具有numify
的常规标量,但根据您的性能要求,这是可选的。
根据您实际需要的精度,您还可以通过以下方式将数字四舍五入,例如sprintf("%.2f",$i)
(仅举个例子:for (my $i = $start; $i <= $end; $i = 0+sprintf("%.2f",$i+$step) )
(。 正如@ikegami在评论中指出的那样,另一种可能性是使用整数并最后进行除法,例如map { $_/100 } -300 .. -270
.