我遇到了代码:
sub insertDecimal
{
my $number = shift;
my $sigDigRight = shift;
if ($number =~ /./) { return ($number); }
elsif (length $number < $sigDigRight) { return ($number); }
else
{
my $leftSide = substr($number, 0, (length $number)-$sigDigRight);
my $rightSide = substr($number, (length $number)-$sigDigRight, );
return ($leftSide . "." . $rightSide);
}
}
我希望改进/重写为:
sub insertDecimal
{
my ($number, $sigDigRight) = @_;
return $number if index ($number, '.') != -1 or length $number < $sigDigRight;
# YES! substr takes an LVALUE ... perldoc it for more :)
substr($number, -$sigDigRight, 0) = '.';
return $number;
}
令我非常惊讶的是,一些 74 毫米唱片的运行在第二版中几乎没有任何改进。
问题:
- 有人会溢出更好的方法来使插入十进制更有效率吗?
- 为什么我根本没有看到任何改进(在 74MM 记录上只好了一分钟)? 如果Perl
- 编译器正在重新调整第一个版本的代码以提高效率,那么无论如何我可以看到Perl选择的改进的执行路径吗?
这两个例程似乎执行的工作量基本相同:
-
扫描
$number
单个字符(任何编译器都应该能够将该正则表达式匹配减少到index
) -
将
$number
长度与限制进行比较 -
可能会在
$number
某处插入单个字符
使用左值substr
(或者,只是利用第四个参数来substr
)可能会使插入更有效率,但毕竟,事情必须移动。
在我看来,优化的最大机会来自将长度检查移到小数点检查之前。
我很想重写你的例程
sub insertDecimal {
my ($number, $sigDigRight) = @_;
return $number if length($number) < $sigDigRight;
return $number if index($number, '.') >= 0;
substr($number, -$sigDigRight, 0, '.');
$number;
}
我发现简单的决定和简短的线条更容易理解。我认为这不应该改变函数的正确性。
一个丑陋的选择是:
sub gah {
my ($number, $sigDigRight) = @_;
my $n = length($number) - $sigDigRight;
return $number unless $n > 0;
$number =~ s{A ([^.]{$n}) ([^.]+) z}{$1.$2}x;
$number;
}
这将检查.
与更换操作相结合。
同样,我不能确定这是正确的,但这是您需要探索的东西。
我可能不会选择gah
,除非改进超过至少一个小时左右的 20%。在我的系统上,它将一个简单的示例减慢了 1,000%。