Good catch. My test framework had a couple of bugs that let me miss that. I've corrected the framework errors, corrected my logical vs bitwise xor error and added the two contributions by anon monks to the tests. It changed the rankings - snowhare4 moved from about 9th to 2nd behind anonmonk1 after fixing. However, anonmonk1 got 3 test case failures, so snowhare4 is now the fastest of the correct solutions. It's nice that the solution that is to me the most elegant is also the fastest correct solution.
#!/usr/bin/perl
use strict;
use Benchmark;
use Data::Dumper;
use List::Util qw (sum);
use List::MoreUtils qw (true);
my $Test_Results = {};
my @Test_Cases = (
[qw (0 0 2 1 002)], [qw (0 2 1 0 021)],
[qw (0 0 0 0 000)], [qw (0 0 1 1 001)],
[qw (0 1 0 1 010)], [qw (0 1 1 0 011)],
[qw (1 0 0 1 100)], [qw (1 0 1 0 101)],
[qw (1 1 0 0 110)], [qw (1 1 1 0 111)],
);
my $test_result_timings = timethese(500000, {
'a_null_sub' => sub { test_framework('a_null_sub', \&a_null_sub
+); },
'snowhare1' => sub { test_framework('snowhare1', \&snowhare1)
+; },
'snowhare2' => sub { test_framework('snowhare2', \&snowhare2)
+; },
'snowhare3' => sub { test_framework('snowhare3', \&snowhare3)
+; },
'snowhare4' => sub { test_framework('snowhare4', \&snowhare4)
+; },
'snowhare5' => sub { test_framework('snowhare5', \&snowhare5)
+; },
'snowhare6' => sub { test_framework('snowhare6', \&snowhare6)
+; },
'saintmike1' => sub { test_framework('saintmike1', \&saintmike1
+); },
'saintmike2' => sub { test_framework('saintmike2', \&saintmike2
+); },
'tye1' => sub { test_framework('tye1', \&tye1);
+ },
'tye2' => sub { test_framework('tye2', \&tye2);
+ },
'ph713_1' => sub { test_framework('ph713_1', \&ph713_1);
+ },
'tanktalus1' => sub { test_framework('tanktalus1', \&tanktalus1
+); },
'davido1' => sub { test_framework('davido1', \&davido1);
+ },
'ikegami1' => sub { test_framework('ikegami1', \&ikegami1);
+ },
'strat1' => sub { test_framework('strat1', \&strat1);
+ },
'strat2' => sub { test_framework('strat2', \&strat2);
+ },
'jamesnc1' => sub { test_framework('jamesnc1', \&jamesnc1);
+ },
'anonmonk1' => sub { test_framework('anonmonk1', \&anonmonk1)
+; },
'knom1' => sub { test_framework('knom1', \&knom1);
+ },
}
);
my $tare_timing = $test_result_timings->{'a_null_sub'};
my @result_ids = sort keys %$test_result_timings;
my $compensated_results = {};
my $fastest;
my %error_results = ();
foreach my $result_label (@result_ids) {
next if ($result_label eq 'a_null_sub');
my $result_timing = $test_result_timings->{$result_label};
my $compensated_time = timediff($result_timing, $tare_timing);
my $cpu_secs = $compensated_time->[1];
$compensated_results->{$result_label} = $cpu_secs;
if (defined $fastest) {
if ($cpu_secs < $compensated_results->{$fastest}) {
$fastest = $result_label;
}
} else {
$fastest = $result_label;
}
foreach my $test_case (@Test_Cases) {
my $test_pattern = $test_case->[4];
$error_results{$result_label} += $Test_Results->{$result_label}
+->{$test_pattern};
}
}
my $fastest_result = $compensated_results->{$fastest};
my @sorted_result_ids = sort { $compensated_results->{$a} <=> $compens
+ated_results->{$b} } keys %$compensated_results;
foreach my $final_result_id (@sorted_result_ids) {
my $cpu_secs = $compensated_results->{$final_result_id};
printf "%20s : %5.2f secs %5.0f\% (%s errors)\n", $final_result_id
+, $cpu_secs, (100 * $cpu_secs / $fastest_result), $error_results{$fin
+al_result_id};
}
exit;
###
sub test_framework {
my ($test_id, $test_sub) = @_;
foreach my $test_case (@Test_Cases) {
my $result = &$test_sub($test_case->[0],$test_case->[1],$test_c
+ase->[2]) ? 1 : 0;
my $error = ($result xor $test_case->[3]) ? 1 : 0;
$Test_Results->{$test_id}->{$test_case->[4]} = $error;
}
}
###
sub a_null_sub {
return 0;
}
sub anonmonk1 {
return $_[0] && !$_[1] && !$_[2] or !$_[0] && ($_[1] xor $_[2]);
}
sub knom1 {
my $count;
foreach (@_) { $count++ if($_); }
return 1 == $count;
}
sub snowhare1 {
return 1 == ($_[0] ? 1 : 0) + ($_[1] ? 1 : 0) + ($_[2] ? 1 :0);
}
sub snowhare2 {
return 2 == (! $_[0]) + (! $_[1]) + (! $_[2]);
}
sub snowhare3 {
return ($_[0] || $_[1] || $_[2]) && (! ($_[0] && $_[1])) && (! ($_
+[1] && $_[2])) && (! ($_[2] && $_[0]));
}
sub snowhare4 {
return (! ($_[0] && $_[1] && $_[2])) && ($_[0] xor $_[1] xor $_[2
+]);
}
sub snowhare5 {
use integer;
return 1 == ($_[0] ? 1 : 0) + ($_[1] ? 1 : 0) + ($_[2] ? 1 :0);
}
sub snowhare6 {
use integer;
return 2 == (! $_[0]) + (! $_[1]) + (! $_[2]);
}
sub saintmike2 {
return 1 == (grep {$_} $_[0],$_[1],$_[2]);
}
sub saintmike1 {
my $count = 0;
$_[0] && $count++;
$_[1] && $count++;
$_[2] && $count++;
return 1 == $count;
}
sub tye1 {
return 1 == grep $_, $_[0], $_[1], $_[2];
}
sub tye2 {
return 1 == !!$_[0] + !!$_[1] + !!$_[2];
}
sub ph713_1 {
return 1 == sum( map { !!$_ } @_);
}
sub tanktalus1 {
return 1 == sum( map { $_ ? 1 : 0 } @_ );
}
sub davido1 {
return 1 == true { $_ } @_;
}
sub ikegami1 {
my $count = 0;
$_ && $count++ foreach @_;
return $count == 1;
}
sub strat1 {
my $count = 0;
$_ and $count++ for (@_);
return 1 == $count;
}
sub strat2 {
1 == do {my $cnt=0; $_ and $cnt++ for (@_); $cnt }
}
sub jamesnc1 {
my $t = 1;
for (@_) { $t = $t<<1 if $_; }
return 2 == $t;
}