为什么perl在这里有浮点错误?

为什么perl在这里有浮点错误?,perl,floating-point,Perl,Floating Point,我有以下代码: sub range { my ($start, $end, $step) = @_; if($step == 0) { die("Step size cannot be 0!") } if($start > $end) { ($start, $end) = ($end, $start); } my @range =

我有以下代码:

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;
}
我得到以下列表:

...
$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机器上安装了PerlV5.24.1。添加bignum模块不会改变计算的变量是错误的这一事实

此外,在执行诸如“-2.7-0.01”之类的操作时也不会发生这种情况

为什么会发生这种情况

请参见

添加bignum模块不会改变计算的变量是错误的这一事实

我猜您添加了
使用bignum
位于
子范围内,但由于其作用域是有限的,因此不会自动影响传递到该
子范围内的变量。因此,
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::BigFloat
等(包括通过
bignum
和相关的pragmas)对象到处都会减慢代码的速度,因此这可能是过分的。为了只在上面的
中使用对象,我使用
numify
将对象降级为常规标量,但这是可选的,取决于您的性能要求


根据您实际需要的精度,您也可以通过例如
sprintf(“%.2f”,$i)
(例如:
for(my$i=$start;$i请您向我们展示一个调用range的示例。例如range(1,10,1);我认为这是一个浮点数的显示问题。请尝试使用printf(“%.2f\n”,$”运行它)对于@range;而不是Data::DumperInestentily
my@range=map{-3+$\u/100}0..30
不会给我四舍五入errors@Håkon Hægland,当然可以。不可能将二进制周期性数字存储为浮点数。您可以通过
printf(“%.20g”,$”看到错误);
。它确实有避免错误累积的好处。@JonathanGreszwinsky问题是1/10在二进制中是周期性的(就像1/3在十进制中一样),因此它不能准确地存储在浮点数中。除此之外,反复添加不准确的数字会使问题变得更糟。BigFloat仍然会遇到同样的问题。无论你将浮点数设置得多大,你都不能将二进制周期数存储到浮点数中。BigRat可以工作,但这肯定是过火了。
映射{$\u0/0.01}-300..-270
可以避免错误累积,取整或公差可以处理剩余的部分。@ikegami谢谢,已编辑。额外的
使用bignum;
是我忘记删除的测试代码中的一个痕迹,我将示例代码切换到
Math::BigRat
,因为我的目的是展示如何尽可能精确地完成它有可能,但我强调这可能是过火了。
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;
}