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\', $CheckDigit ) );
        } while ( $CheckDigit > 9 );
    },
    unpack_star => sub {
        my $CheckDigit = \"999989989\";
        do {
            $CheckDigit = sum( unpack( \'(A)*\', $CheckDigit ) );
        } while ( $CheckDigit > 9 );
    },
    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*\', pack( \'S9\', unpack( \'AAAAAAAAA\', $CheckDigit ) ) );
        } while ( $CheckDigit > 9 );
    },
    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。     

要回复问题请先登录注册