in reply to Re^2: minimum, maximum and average of a list of numbers at the same time
in thread minimum, maximum and average of a list of numbers at the same time
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) } })
Rate algorithm simple algorithm 1517/s -- -30% simple 2177/s 44% --
-xdg
Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.
|
|---|