use strict; use warnings; use autodie; use v5.12; use Benchmark qw/cmpthese/; use Test::More tests => 4; use Inline 'C' => 'DATA'; use constant TOP => 200000; use constant TIME => 10; note "Operating system: $^O, Perl version: $^V\n\n"; note "Constant TOP is ", TOP; note "Constant TIME is ", TIME, "\n\n"; is( scalar @{ basic_perl( 3571 ) }, 500, "basic_perl(3571): The first 500 primes are found from 2 to 3571." ); is_deeply( external_cpp(TOP), basic_perl(TOP), "external_cpp(TOP): Same results as basic_perl(TOP)." ); is_deeply( inline_c_list(TOP), basic_perl(TOP), "inline_c_list(TOP): Same results as basic_perl(TOP)." ); is_deeply( inline_c_aref(TOP), basic_perl(TOP), "inline_c_aref(TOP): Same result as basic_perl(TOP)." ); note "\nComparing basic_perl(), external_cpp(), inline_c_list(), inline_c_aref()\n", "for ", TIME, " seconds searching ", TOP, " integers.\n\n"; cmpthese( - TIME, { basic_perl => \&basic_perl, external_cpp => \&external_cpp, inline_c_list => \&inline_c_list, inline_c_aref => \&inline_c_aref, }, ); note "\nI love it when a plan comes together.\n\n"; # The pure Perl version. sub basic_perl { my $top = $_[0] // TOP; my @primes = ( 2 ); BASIC_OUTER: for( my $i = 3; $i <= $top; $i += 2 ) { my $sqrt_i = sqrt( $i ); for( my $j = 3; $j <= $sqrt_i ; $j += 2 ) { next BASIC_OUTER unless $i % $j; } push @primes, $i; } return \@primes; } # A wrapper around the external executable compiled in C++. sub external_cpp { my $top = $_[0] // TOP; open my $fh, '-|', "primes $top"; chomp( my @primes = <$fh> ); close $fh; return \@primes; } # To be consistent: a wrapper around the Inline C version. sub inline_c_list{ my $top = $_[0] // TOP; my @primes = inline_c_list_primes( $top ); return \@primes; } sub inline_c_aref{ my $top = $_[0] // TOP; return inline_c_aref_primes( $top ); } __END__ // Reference only (not used by Inline::C ) // The source code, "primes.cpp" for "primes.exe", // used by external_cpp(). #include #include #include #include #include using namespace std; vector get_primes( int search_to ); void print( int value ); // The first 500 primes are found from 2 to 3571. const int TOP = 3571; // http://en.wikipedia.org/wiki/List_of_prime_numbers int main(int argc, char *argv[] ) { int search_to = ( argc > 1 ) ? atoi(argv[1]) : TOP; vector primes = get_primes( search_to ); for_each( primes.begin(), primes.end(), print ); return 0; } vector get_primes( int search_to ) { vector primes; primes.push_back(2); for( int i = 3; i <= search_to; i += 2 ) { int sqrt_i = sqrt( i ); for( int j = 3; j <= sqrt_i; j += 2 ) { if( i % j == 0 ) goto SKIP; } primes.push_back(i); SKIP: {}; } return primes; } void print ( int value ) { cout << value << endl; } __C__ #include "math.h" void inline_c_list_primes( int search_to ) { Inline_Stack_Vars; Inline_Stack_Reset; Inline_Stack_Push(sv_2mortal(newSViv(2))); int i; for( i = 3; i <= search_to; i+=2 ) { int sqrt_i = sqrt( i ); int qualifies = 1; int j; for( j = 3; (j<=sqrt_i) && (qualifies==1); j += 2 ) { if( i % j == 0 ) { qualifies = 0; } } if( qualifies == 1 ) { Inline_Stack_Push(sv_2mortal(newSViv(i))); } } Inline_Stack_Done; } AV * inline_c_aref_primes ( int search_to ) { AV* av; av = newAV(); av_push( av, newSViv( 2 ) ); int i; for( i = 3; i <= search_to; i+=2 ) { int sqrt_i = sqrt( i ); int qualifies = 1; int j; for( j = 3; (j<=sqrt_i) && (qualifies==1); j += 2 ) { if( i % j == 0 ) { qualifies = 0; } } if( qualifies == 1 ) { av_push( av, newSViv( i ) ); } } return sv_2mortal( av ); }