After finding that oops above in my code, I thought I better put correctness tests in and publish the code I was using so that other people could tell me I was nuts if necessary.
So here again is the output of the benchmark code:
==== Correctness tests ====
Probabilities are: {6 => 27.000, 19 => 23.000, 21 => 33.000, 43 => 17.
+000}
origCode yielded {6 => 26.955, 19 => 22.825, 21 => 33.142, 43 => 17.07
+8}
duff yielded {6 => 27.111, 19 => 22.956, 21 => 33.008, 43 => 16.925}
fizbin yielded {6 => 27.117, 19 => 23.057, 21 => 32.862, 43 => 16.964}
L~R yielded {6 => 26.929, 19 => 22.946, 21 => 33.151, 43 => 16.974}
QM yielded {6 => 59.902, 19 => 0.000, 21 => 17.062, 43 => 23.036}
QM failed
ccn yielded {6 => 26.991, 19 => 22.882, 21 => 33.064, 43 => 17.063}
==== Speed tests ====
Rate origCode duff QM L~R ccn fizbin
origCode 4101/s -- -34% -78% -83% -87% -89%
duff 6191/s 51% -- -66% -75% -81% -83%
QM 18348/s 347% 196% -- -26% -43% -50%
L~R 24743/s 503% 300% 35% -- -24% -32%
ccn 32411/s 690% 424% 77% 31% -- -11%
fizbin 36567/s 792% 491% 99% 48% 13% --
And here's the code I used to make that determination. The formatting is from being run through
perltidy, since it was even uglier before.
#!perl
use strict;
my $str = "17:43:33:21:23:19:27:6";
my $codehash = {
origCode => sub {
my @ary;
my %hash = split /:/, $str;
foreach my $k ( keys %hash ) {
push( @ary, map { $hash{$k} } ( 1 .. $k ) );
}
my $adId = $ary[ int( rand(100) ) ];
},
ccn => sub {
my %hash = split /:/, $str;
my $adno;
my $rand = rand 100;
my $sum = 0;
for ( keys %hash ) { # there is no need of sorted keys
$adno = $hash{$_};
last if ( $sum += $_ ) > $rand;
}
$adno;
},
QM => sub {
my %hash = reverse split /:/, $str;
my $count;
my %ad_lookup;
foreach my $k ( keys %hash ) {
$count += $hash{$k};
$ad_lookup{$count} = $k;
}
my $rand = rand(100);
my $adid;
foreach ( sort { $a <=> $b } keys %ad_lookup ) {
$adid = $ad_lookup{$_} unless defined($adid);
if ( $_ <= $rand ) {
$adid = $ad_lookup{$_};
}
else {
last;
}
}
$adid;
},
"L~R" => sub {
my $lookup;
my %hash = reverse split /:/, $str;
while ( my ( $key, $val ) = each %hash ) {
$lookup .= pack( "C*", ($key) x $val );
}
my $addid = unpack( "C", substr( $lookup, rand 100, 1 ) );
},
duff => sub {
my @ary;
my @a = split /:/, $str;
@a % 2 && die; # not an even number of items
while ( my ( $p, $ad ) = splice @a, 0, 2 ) {
push @ary, ($ad) x $p;
}
my $adId = $ary[ int( rand(100) ) ];
},
fizbin => sub {
my @a = split /:/, $str;
@a % 2 && die; # not an even number of items
my $r = int( rand(100) );
my ( $adId, $p );
while ( ( $p, $adId ) = splice @a, 0, 2 ) {
if ( $r < $p ) { last; }
$r -= $p;
}
$adId;
}
};
sub phash (%) {
my %h = @_;
return "{"
. join( ", ",
map { sprintf( '%s => %3.3f', $_, $h{$_} ); }
sort { $a <=> $b } keys(%h) )
. "}";
}
print "==== Correctness tests ==== \n\n";
my %strhash = reverse split( /:/, $str );
print "Probabilities are: ", phash(%strhash), "\n";
foreach my $subname ( keys %$codehash ) {
my %resultshash = map { $_ => 0 } keys %strhash;
do { $resultshash{ $codehash->{$subname}->() } += 0.001; }
for ( 1 .. 100000 );
print "$subname yielded ", phash(%resultshash), "\n";
do {
print "$subname failed\n" and last
if ( abs( $resultshash{$_} - $strhash{$_} ) > 0.5 );
}
for keys(%strhash);
}
print "\n==== Speed tests ====\n\n";
use Benchmark qw(cmpthese);
cmpthese( -5, $codehash );
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.