This is an automated email from the git hooks/post-receive script. ppm-guest pushed a commit to annotated tag v0.13 in repository libmath-prime-util-perl.
commit 050e1858073a16c81d4a3d05ec3ef9e3709909f9 Author: Dana Jacobsen <d...@acm.org> Date: Fri Oct 19 01:54:48 2012 -0600 More primes.pl changes, and script test does multiple filters --- bin/primes.pl | 171 ++++++++++++++++++++++++----------------- examples/test-primes-script.pl | 44 ++++++++--- 2 files changed, 135 insertions(+), 80 deletions(-) diff --git a/bin/primes.pl b/bin/primes.pl index 80bfb7d..5d7a427 100755 --- a/bin/primes.pl +++ b/bin/primes.pl @@ -65,7 +65,6 @@ GetOptions(\%opts, die_usage() if exists $opts{'help'}; Math::Prime::Util::prime_set_config(gmp=>0) if exists $opts{'nompugmp'}; - # Get the start and end values. Verify they're positive integers. die_usage() unless @ARGV == 2; my ($start, $end) = @ARGV; @@ -81,13 +80,58 @@ if ( ($start >= ~0 && $start ne ~0) || ($end >= ~0 && $end ne ~0) ) { $end = Math::BigInt->new($end); } +# Calculate the mod 210 pre-test. This helps with the individual filters, +# but the real benefit is that it convolves the pretests, which can speed +# up even more. +my ($min_pass, %mod_pass) = find_mod210_restriction(); +# Find out if they've filtered so much nothing passes (e.g. cousin quad) +if (scalar keys %mod_pass == 0) { + $end = $min_pass if $end > $min_pass; +} + +if ($start > $end) { + # Do nothing +} elsif (exists $opts{'lucas'} || + exists $opts{'fibonacci'} || + exists $opts{'euclid'} || + exists $opts{'mersenne'} + ) { + my @p = gen_and_filter($start, $end); + print join("\n", @p), "\n" if scalar @p > 0; +} else { + my @p; + while ($start <= $end) { + + # Adjust segment sizes for some cases + $segment_size = 10000 if $start > ~0; # small if doing bigints + if (exists $opts{'pillai'}) { + $segment_size = ($start < 10000) ? 100 : 1000; # very small for Pillai + } + if (exists $opts{'palindromic'}) { + $segment_size = 10**length($start) - $start - 1; # all n-digit numbers + } + + my $seg_start = $start; + my $seg_end = $start + $segment_size; + $seg_end = $end if $end < $seg_end; + $start = $seg_end+1; + + @p = gen_and_filter($seg_start, $seg_end); + + # print this segment + print join("\n", @p), "\n" if scalar @p > 0; + } +} + + # Fibonacci numbers { - my @fibs = (Math::BigInt->new(0), Math::BigInt->new(1)); + my @fibs; sub fib { my $n = shift; return $n if $n < 2; if (!defined $fibs[$n]) { + @fibs = (Math::BigInt->new(0), Math::BigInt->new(1)) if scalar @fibs == 0; my ($nm2, $nm1) = ($fibs[-2],$fibs[-1]); for (scalar @fibs .. $n) { ($nm2, $nm1) = ($nm1, $nm2 + $nm1); @@ -265,44 +309,46 @@ sub gen_and_filter { } } + if (exists $opts{'twin'} && !defined $gen) { + @p = @{primes($start, $end)}; + push @p, is_prime($p[-1]+2) ? $p[-1]+2 : 0; + my @twin; + my $prime = shift @p; + foreach my $next (@p) { + push @twin, $prime if $prime+2 == $next; + $prime = $next; + } + @p = @twin; + $gen = 'twin'; + } + if (!defined $gen) { @p = @{primes($start, $end)}; $gen = 'primes'; } - if (exists $opts{'twin'}) { - if ($gen ne 'primes') { - @p = grep { is_prime( $_+2 ); } @p; - } elsif (scalar @p > 0) { - # All primes in the range are here, so just look in the array. - push @p, is_prime($p[-1]+2) ? $p[-1]+2 : 0; - my @twin; - my $prime = shift @p; - foreach my $next (@p) { - push @twin, $prime if $prime+2 == $next; - $prime = $next; - } - @p = @twin; - } + # Apply the mod 210 pretest + if ($min_pass > 0) { + @p = grep { $_ <= $min_pass || exists $mod_pass{$_ % 210} } @p; } - if (exists $opts{'triplet'}) { # could be optimized like twin + if (exists $opts{'twin'} && $gen ne 'twin') { + @p = grep { is_prime( $_+2 ); } @p; + } + + if (exists $opts{'triplet'}) { @p = grep { is_prime($_+6) && (is_prime($_+2) || is_prime($_+4)); } @p; } - if (exists $opts{'quadruplet'}) { # could be optimized like twin - @p = grep { is_prime($_+2) && is_prime($_+6) && is_prime($_+8); } - grep { $_ <= 5 || ($_ % 30) == 11; } - @p; + if (exists $opts{'quadruplet'}) { + @p = grep { is_prime($_+2) && is_prime($_+6) && is_prime($_+8); } @p; } - if (exists $opts{'cousin'}) { # could be optimized like twin - @p = grep { is_prime($_+4); } - grep { ($_ <= 3) || ($_ % 6) == 1; } - @p; + if (exists $opts{'cousin'}) { + @p = grep { is_prime($_+4); } @p; } - if (exists $opts{'sexy'}) { # could be optimized like twin + if (exists $opts{'sexy'}) { @p = grep { is_prime($_+6); } @p; } @@ -312,24 +358,14 @@ sub gen_and_filter { @p; } if (exists $opts{'sophie'}) { - my %mod210; - undef @mod210{11,23,29,41,53,71,83,89,113,131,149,173,179,191,209}; - @p = grep { is_prime( 2*$_+1 ); } - grep { $_ <= 5 || exists $mod210{$_ % 210} } - @p; + @p = grep { is_prime( 2*$_+1 ); } @p; } if (exists $opts{'cuban1'}) { - my %mod210; - undef @mod210{1,19,37,61,79,121,127,169,187}; - @p = grep { my $n = sqrt((4*$_-1)/3); $n == int($n); } - #grep { ($_%3) == 1 } - grep { $_ <= 7 || exists $mod210{$_ % 210} } - @p; + #@p = grep { my $n = sqrt((4*$_-1)/3); $n == int($n); } @p; + @p = grep { my $n = sqrt((4*$_-1)/3); 4*$_ == int($n)*int($n)*3+1; } @p; } if (exists $opts{'cuban2'}) { - @p = grep { my $n = sqrt(($_-1)/3); $n == int($n); } - grep { ($_%3) == 1 } - @p; + @p = grep { my $n = sqrt(($_-1)/3); $_ == int($n)*int($n)*3+1; } @p; } if (exists $opts{'pnm1'}) { @p = grep { is_prime( primorial(Math::BigInt->new($_))-1 ) } @p; @@ -346,40 +382,37 @@ sub gen_and_filter { @p; } -if (exists $opts{'lucas'} || - exists $opts{'fibonacci'} || - exists $opts{'euclid'} || - exists $opts{'mersenne'}) { - my @p = gen_and_filter($start, $end); - print join("\n", @p), "\n" if scalar @p > 0; -} else { - my @p; - while ($start <= $end) { - - # Adjust segment sizes for some cases - $segment_size = 10000 if $start > ~0; # small if doing bigints - if (exists $opts{'pillai'}) { - $segment_size = ($start < 10000) ? 100 : 1000; # very small for Pillai - } - if (exists $opts{'palindromic'}) { - $segment_size = 10**length($start) - $start - 1; # all n-digit numbers +sub find_mod210_restriction { + my %mods_left; + undef @mods_left{ grep { ($_%2) && ($_%3) && ($_%5) && ($_%7) } (0..209) }; + + my %mod210_restrict = ( + cuban1 => {min=> 7, mod=>[1,19,37,61,79,121,127,169,187]}, + cuban2 => {min=> 2, mod=>[1,13,43,109,139,151,169,181,193]}, + twin => {min=> 5, mod=>[11,17,29,41,59,71,101,107,137,149,167,179,191,197,209]}, + triplet => {min=> 7, mod=>[11,13,17,37,41,67,97,101,103,107,137,163,167,187,191,193]}, + quadruplet => {min=> 5, mod=>[11,101,191]}, + cousin => {min=> 7, mod=>[13,19,37,43,67,79,97,103,109,127,139,163,169,187,193]}, + sexy => {min=> 7, mod=>[11,13,17,23,31,37,41,47,53,61,67,73,83,97,101,103,107,121,131,137,143,151,157,163,167,173,181,187,191,193]}, + safe => {min=>11, mod=>[17,23,47,53,59,83,89,107,137,143,149,167,173,179,209]}, + sophie => {min=> 5, mod=>[11,23,29,41,53,71,83,89,113,131,149,173,179,191,209]}, + # Nothing for good, pillai, palindromic, fib, lucas, mersenne, primorials + ); + + my $min = 0; + while (my($filter,$data) = each %mod210_restrict) { + next unless exists $opts{$filter}; + $min = $data->{min} if $min < $data->{min}; + my %thismod; + undef @thismod{ @{$data->{mod}} }; + foreach my $m (keys %mods_left) { + delete $mods_left{$m} unless exists $thismod{$m}; } - - my $seg_start = $start; - my $seg_end = $start + $segment_size; - $seg_end = $end if $end < $seg_end; - $start = $seg_end+1; - - @p = gen_and_filter($seg_start, $seg_end); - - # print this segment - print join("\n", @p), "\n" if scalar @p > 0; } + return ($min, %mods_left); } - - sub die_usage { die <<EOU; Usage: $0 [options] START END diff --git a/examples/test-primes-script.pl b/examples/test-primes-script.pl index e91ccdb..7f3390f 100755 --- a/examples/test-primes-script.pl +++ b/examples/test-primes-script.pl @@ -31,16 +31,27 @@ my @test_data = ( [18239, "Euclid", "--euclid", 0], ); my %oeis_name = map { $_->[0] => $_->[1] } @test_data; +my %oeis_number = map { my $n=$_->[2]; $n=~s/^--//; $n => $_->[0] } @test_data; + +# Verify additional filters +my @additional_filters; +foreach my $name (@ARGV) { + $name =~ s/^--//; + die "Unknown filter: $name\n" unless defined $oeis_number{$name}; + push @additional_filters, $name; +} my $test_data_hash = read_script_data('script-test-data.bs'); +if (@additional_filters > 0) { + print "Additional Filters: ", join(" ", @additional_filters), "\n"; +} foreach my $test (@test_data) { my $oeis_no = $test->[0]; - my $test_data = $test_data_hash->{$oeis_no}; - if (!defined $test_data) { + if (!defined $test_data_hash->{$oeis_no}) { die "No test data found for OEIS $oeis_no : $test->[1] primes\n"; } - test_oeis(@$test, $test_data); + test_oeis(@$test, $test_data_hash); } @@ -49,6 +60,9 @@ foreach my $test (@test_data) { sub read_script_data { my ($filename) = @_; + die "Can't find test file: $filename\nRun make-script-test-data.pl\n" + unless -r $filename; + my $stream = Data::BitStream::XS->new( file => $filename, mode => 'ro' ); my %hash; @@ -89,20 +103,28 @@ sub read_script_data { } sub test_oeis { - my($oeis_no, $name, $script_arg, $restrict, $ref_data) = @_; + my($oeis_no, $name, $script_arg, $restrict, $test_data_hash) = @_; + + my @ref = @{ $test_data_hash->{$oeis_no} }; + my $end = $ref[-1]; + + foreach my $filter_name (@additional_filters) { + my $filter_no = $oeis_number{$filter_name}; + my %filter_data; + undef @filter_data{ @{$test_data_hash->{$filter_no}} }; + my $filter_end = $test_data_hash->{$filter_no}->[-1]; + @ref = grep { exists $filter_data{$_} } @ref; + $script_arg .= " --$filter_name"; + $end = $filter_end if $end > $filter_end; # bring endpoint down + } - my @ref = @$ref_data; printf "%12s primes (OEIS A%06d): generating..", $name, $oeis_no; - #print "\n"; - #print "reference data:\n"; - #print " $_\n" for @ref; - #print "primes.pl $script_arg 1 $ref[-1]\n"; my $start = [gettimeofday]; - my @scr = split /\s+/, qx+$FindBin::Bin/../bin/primes.pl $script_arg 1 $ref[-1]+; + my @scr = split /\s+/, qx+$FindBin::Bin/../bin/primes.pl $script_arg 1 $end+; { no bigint; - my $num_generated = scalar @scr; + my $num_generated = scalar @scr || 0.1; my $seconds = tv_interval($start); my $msperprime = ($seconds * 1000.0) / $num_generated; printf " %7d. %7.2f ms/prime\n", $num_generated, $msperprime; -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libmath-prime-util-perl.git _______________________________________________ Pkg-perl-cvs-commits mailing list Pkg-perl-cvs-commits@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-perl-cvs-commits