Found a slightly different implementation here: https://github.com/bdlightner/luhn-implementation-Perl-
But, it's a little slower:
$ perl ./script
Benchmark: timing 10 iterations of Algorithm::LUHN, bdlightner...
Algorithm::LUHN: 7 wallclock secs ( 6.89 usr + 0.00 sys = 6.89 CPU) @ 1.45/s (n=10)
bdlightner: 8 wallclock secs ( 7.69 usr + 0.00 sys = 7.69 CPU) @ 1.30/s (n=10)
The benchmark code and both implementations:
#!/usr/bin/perl
use Benchmark;
my %map = map { $_ => $_ } 0..9;
# cd1 is from https://metacpan.org/pod/Algorithm::LUHN
sub cd1 {
my @buf = reverse split //, shift;
my $totalVal = 0;
my $flip = 1;
foreach my $c (@buf) {
my $posVal = $map{$c};
$posVal *= 2 unless $flip = !$flip;
while ($posVal) {
$totalVal += $posVal % 10;
$posVal = int($posVal / 10);
}
}
return (10 - $totalVal % 10) % 10;
}
# cd2 is from: https://github.com/bdlightner/luhn-implementation-Perl-
sub cd2 {
my($number) = @_;
my($i, $sum, $ch, $num, $twoup, $len);
$len = length($number);
$sum = 0;
$twoup = 1;
for ($i = $len - 1; $i >= 0; --$i) {
$ch = substr($number, $i, 1);
$num = unpack('c', $ch) - 0x30;
$num += $num if ($twoup);
$num = int($num / 10) + ($num % 10) if ($num > 9);
$sum += $num;
$twoup = (++$twoup) & 1;
}
$sum = 10 - ($sum % 10);
$sum = 0 if ($sum == 10);
return $sum;
}
# example use:
my @range=(401135000000000..401135000099999);
timethese(10, {
'Algorithm::LUHN' => sub { for(@range){cd1($_)} },
'bdlightner' => sub { for(@range){cd2($_)} },
});