I've taken a cut at trying to get as perlish as possible with algorithm, eliminating as much overhead as I could quickly think of (and keeping similar approaches on dereferencing, etc.). The simple approach is still faster in pure perl -- doing the array overhead manually with splice versus using for still swamps the comparision savings.
use strict;
use warnings;
use Benchmark qw(cmpthese);
sub algorithm {
my $ref = shift;
return (undef,undef,undef) if ! $ref;
my @ary = @$ref;
my ( $min, $max, $tot );
if (@ary % 2) {
$min = $max = $tot = shift( @ary );
}
else {
($min, $max) = ($ary[0] < $ary[1])
? ($ary[0], $ary[1])
: ($ary[1], $ary[0]);
$tot = $min + $max;
splice( @ary, 0, 2 );
}
while ( @ary ) {
if ( $ary[0] < $ary[1] ) {
$min = $ary[0] if ( $ary[0] < $min );
$max = $ary[1] if ( $ary[1] > $max );
}
else {
$min = $ary[1] if ( $ary[1] < $min );
$max = $ary[0] if ( $ary[0] > $max );
}
$tot += $ary[0] + $ary[1];
splice( @ary, 0, 2 );
}
return ( $min, $max, $tot / @$ref );
}
sub simple {
my $r = shift;
if (@$r) {
my ($min, $max, $tot) = ($r->[0]) x 3;
for (@$r[ 1 .. $#{$r}]) {
$min = $_ if $_ < $min;
$max = $_ if $_ > $max;
$tot += $_;
}
return ($min, $max, $tot / @$r);
}
return (undef, undef, undef)
}
my @nums = map { rand } ( 1 .. 1000 );
# verify they do the same thing!
# print "simple: @{[simple(\@nums)]}\n";
# print "algorithm: @{[algorithm(\@nums)]}\n";
cmpthese(-1, { algorithm => sub { my @r = algorithm(\@nums) },
simple => sub { my @r = simple(\@nums) } })