perl - 为什么 perl 这里有浮点错误?
问题描述
我有这个代码:
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 模块并不会改变计算出的变量错误的事实。
我猜use bignum;
你sub range
添加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 在评论中指出的那样,另一种可能性是使用整数并最后进行除法,如 eg map { $_/100 } -300 .. -270
。
推荐阅读
- ethereum - 以太坊网络可以用作数据库吗
- flutter - 在 Flutter 的输入装饰中为 labelText 添加强制(*)
- android - 无法在单个配置中同时重置俯仰、航向、边界、中心坐标
- flutter - 在颤振视频播放器中运行视频时出错
- reactjs - “种子”未定义为 no-undef。seed.js 有 IIFE
- android - 微调器自定义样式未正确应用
- c - Do a function that transform a string in int from a base
- twilio - After creating conference in Twilio Flex using voice API, how do I add hangup button call controls for each participant?
- angular - How to reset the mapView if there is a dynamic content to be showed in the snazzy window popup?
- sql - literal does not match format string-version 11