in reply to One out of three ain't bad

In the interest of "if you are going to do it, overdo it", I took the various solutions presented (along with two additional variants; snowhare5 and snowhare6 I thought of) and ran precision benchmarks on them to see how they stack up performance wise in addition to 'elegance wise'. And to verify that they all actually produce correct results. The benchmarks were run with 500,000 loops to get good precision and I 'tare' compensated the scripts with a 'null script' that factored out the testing framework overhead time.

#!/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 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); + }, } ); 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->[5]; $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) { $Test_Results->{$test_id}->{$test_case->[5]} = ($test_case->[3] + ^ &$test_sub($test_case->[0],$test_case->[1],$test_case->[2])) ? 1 : + 0; } } ### sub a_null_sub { return 0; } 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] ^ $_[1] ^ $_[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; }
Results:
snowhare6 : 3.76 secs 100% (0 errors) snowhare2 : 3.90 secs 104% (0 errors) tye2 : 4.06 secs 108% (0 errors) snowhare3 : 4.09 secs 109% (0 errors) snowhare5 : 4.13 secs 110% (0 errors) snowhare1 : 4.73 secs 126% (0 errors) saintmike1 : 5.51 secs 147% (0 errors) tye1 : 5.62 secs 149% (0 errors) snowhare4 : 5.69 secs 151% (0 errors) saintmike2 : 6.37 secs 169% (0 errors) strat1 : 10.60 secs 282% (0 errors) ikegami1 : 11.14 secs 296% (0 errors) tanktalus1 : 11.68 secs 311% (0 errors) strat2 : 11.81 secs 314% (0 errors) jamesnc1 : 12.07 secs 321% (0 errors) ph713_1 : 15.60 secs 415% (0 errors) davido1 : 16.18 secs 430% (0 errors)

The good news is all the solutions produce correct results. (Yay everyone!).

The bad news is that they vary by about 400% performance wise from the fastest to the slowest.

The ranked results were as follows:

snowhare6 : 3.76 secs 100% (0 errors) snowhare2 : 3.90 secs 104% (0 errors) tye2 : 4.06 secs 108% (0 errors) snowhare3 : 4.09 secs 109% (0 errors) snowhare5 : 4.13 secs 110% (0 errors) snowhare1 : 4.73 secs 126% (0 errors) saintmike1 : 5.51 secs 147% (0 errors) tye1 : 5.62 secs 149% (0 errors) snowhare4 : 5.69 secs 151% (0 errors) saintmike2 : 6.37 secs 169% (0 errors) strat1 : 10.60 secs 282% (0 errors) ikegami1 : 11.14 secs 296% (0 errors) tanktalus1 : 11.68 secs 311% (0 errors) strat2 : 11.81 secs 314% (0 errors) jamesnc1 : 12.07 secs 321% (0 errors) ph713_1 : 15.60 secs 415% (0 errors) davido1 : 16.18 secs 430% (0 errors)

snowhare5 and snowhare6 were algorithmically the same as the previously presented snowhare1 and snowhare2 respectively, except I added 'use integer;' to them.

Among the 'trivially generalized to handle N values' scripts, tye1 is the fastest (all it would take is replacing the explict variable callouts with @_).