如何解决Perl中字符串最快的校验位例程是什么?
| 给定一串数字,我必须使用Perl尽可能快地求和所有数字。 我的第一个实现使用unpack()对数字进行解包,然后用List :: Utils \'sum()对数字列表求和。 它的速度非常快,但是此任务有更快的打包/解包配方吗? 我尝试使用打包/解包组合,并对这两种实现进行了基准测试。 使用的cpu时间几乎相同;也许有一些我不知道的快速技巧? 这是我进行基准测试的方法:#!/usr/bin/env perl
use 5.012;
use strict;
use List::Util qw/sum/;
use Benchmark qw/timethese/;
timethese ( 1000000,{
list_util => sub {
my $CheckDigit = \"999989989\";
do {
$CheckDigit = sum( unpack( \'AAAAAAAAA\',$CheckDigit ) );
} while ( $CheckDigit > 9 );
},perl_only => sub {
my $CheckDigit = \"999989989\";
do {
$CheckDigit = unpack( \'%16S*\',pack( \'S9\',unpack( \'AAAAAAAAA\',$CheckDigit ) ) );
} while ( $CheckDigit > 9 );
},} );
解决方法
如何对打包/解包不太聪明,使用简单的拆分,或者在数学上略微聪明并使用模,这使所有其他方法都无法胜任呢?
#!/usr/bin/env perl
use strict;
use List::Util qw/sum/;
use Benchmark qw/timethese/;
my $D=\"99949596\";
timethese ( 1000000,{
naive => sub {
my $CheckDigit= $D;
do {
$CheckDigit = sum( split//,$CheckDigit );
} while ( $CheckDigit > 9 );
},list_util => sub {
my $CheckDigit = $D;
do {
$CheckDigit = sum( unpack( \'AAAAAAAAA\',$CheckDigit ) );
} while ( $CheckDigit > 9 );
},perl_only => sub {
my $CheckDigit = $D;
do {
$CheckDigit = unpack( \'%16S*\',pack( \'S9\',unpack( \'AAAAAAAAA\',$CheckDigit ) ) );
} while ( $CheckDigit > 9 );
},modulo => sub {
my $CheckDigit = $D % 9;
},} );
结果:
Benchmark: timing 1000000 iterations of list_util,modulo,naive,perl_only...
list_util: 5 wallclock secs ( 4.62 usr + 0.00 sys = 4.62 CPU) @ 216450.22/s (n=1000000)
modulo: -1 wallclock secs ( 0.07 usr + 0.00 sys = 0.07 CPU) @ 14285714.29/s (n=1000000)
(warning: too few iterations for a reliable count)
naive: 3 wallclock secs ( 2.79 usr + 0.00 sys = 2.79 CPU) @ 358422.94/s (n=1000000)
perl_only: 6 wallclock secs ( 5.18 usr + 0.00 sys = 5.18 CPU) @ 193050.19/s (n=1000000)
, 解压缩不是分割字符串的最快方法:
#!/usr/bin/env perl
use strict;
use List::Util qw/sum/;
use Benchmark qw/cmpthese/;
cmpthese ( -3,{
list_util => sub {
my $CheckDigit = \"999989989\";
do {
$CheckDigit = sum( unpack( \'AAAAAAAAA\',unpack_star => sub {
my $CheckDigit = \"999989989\";
do {
$CheckDigit = sum( unpack( \'(A)*\',re => sub {
my $CheckDigit = \"999989989\";
do {
$CheckDigit = sum( $CheckDigit =~ /(.)/g );
} while ( $CheckDigit > 9 );
},split => sub {
my $CheckDigit = \"999989989\";
do {
$CheckDigit = sum( split //,$CheckDigit );
} while ( $CheckDigit > 9 );
},perl_only => sub {
my $CheckDigit = \"999989989\";
do {
$CheckDigit = unpack( \'%16S*\',modulo => sub {
my $CheckDigit = \"999989989\";
$CheckDigit = ($CheckDigit+0) && ($CheckDigit % 9 || 9);
},} );
产生:
Rate perl_only list_util re unpack_star split modulo
perl_only 89882/s -- -15% -30% -45% -54% -97%
list_util 105601/s 17% -- -17% -35% -45% -97%
re 127656/s 42% 21% -- -21% -34% -96%
unpack_star 162308/s 81% 54% 27% -- -16% -95%
split 193405/s 115% 83% 52% 19% -- -94%
modulo 3055254/s 3299% 2793% 2293% 1782% 1480% --
因此,如果必须将字符串分成字符,characters5ѭ似乎是最好的选择。
但是,反复对数字求和几乎与取模mod 9相同(如mirod所指出的)。不同之处在于$Digits % 9
产生0而不是9。一个修正的公式是($Digits-1) % 9 + 1
,但是(至少在Perl中)不适用于全零情况(产生9而不是0)。在Perl中有效的表达式是($Digits+0) && ($Digits % 9 || 9)
。第一项处理全零情况,第二项处理正常情况,第三项将0更改为9。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。