[libmath-prime-util-perl] 15/50: Add Lucas, Fibonacci, and Palindromic primes, plus speedups
Partha P. Mukherjee
ppm-guest at moszumanska.debian.org
Thu May 21 18:45:33 UTC 2015
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 b725603e66f81be2f9f80ceda53df3b6cb7cb444
Author: Dana Jacobsen <dana at acm.org>
Date: Wed Oct 17 01:38:52 2012 -0600
Add Lucas, Fibonacci, and Palindromic primes, plus speedups
---
bin/primes.pl | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 134 insertions(+), 18 deletions(-)
diff --git a/bin/primes.pl b/bin/primes.pl
index 9e73a8d..3cdb6fe 100755
--- a/bin/primes.pl
+++ b/bin/primes.pl
@@ -6,22 +6,35 @@ use Getopt::Long;
use Math::Prime::Util qw/primes next_prime is_prime/;
$| = 1;
+# For many more types, see:
+# http://en.wikipedia.org/wiki/List_of_prime_numbers
+# http://mathworld.wolfram.com/IntegerSequencePrimes.html
+
my $show_safe = 0;
my $show_sophie = 0;
my $show_twin = 0;
+my $show_lucas = 0;
+my $show_fibonacci = 0;
+my $show_palindromic = 0;
my $show_usage = 0;
my $segment_size = 30 * 128_000; # 128kB
-GetOptions( "safe" => \$show_safe,
- "sophie" => \$show_sophie,
- "twin" => \$show_twin,
- "help" => \$show_usage,
+GetOptions( "safe" => \$show_safe,
+ "sophie|sg" => \$show_sophie,
+ "twin" => \$show_twin,
+ "lucas" => \$show_lucas,
+ "fibonacci" => \$show_fibonacci,
+ "palindromic|palindrome|palendrome" => \$show_palindromic,
+ "help" => \$show_usage,
) || die_usage();
die_usage() if $show_usage;
# Get the start and end values. Verify they're positive integers.
die_usage() unless @ARGV == 2;
my ($start, $end) = @ARGV;
+# Allow "10**100" as arguments
+$start =~ s/^(\d+)\*\*(\d+)$/Math::BigInt->new($1)->bpow($2)/e;
+$end =~ s/^(\d+)\*\*(\d+)$/Math::BigInt->new($1)->bpow($2)/e;
die "$start isn't a positive integer" if $start =~ tr/0123456789//c;
die "$end isn't a positive integer" if $end =~ tr/0123456789//c;
@@ -31,19 +44,105 @@ if ( ($start >= ~0 && $start ne ~0) || ($end >= ~0 && $end ne ~0) ) {
$end = Math::BigInt->new($end);
}
+# Fibonacci numbers
+{
+ my @fibs = (Math::BigInt->new(0), Math::BigInt->new(1));
+ sub fib {
+ my $n = shift;
+ return $n if $n < 2;
+ if (!defined $fibs[$n]) {
+ my ($nm2, $nm1) = ($fibs[-2],$fibs[-1]);
+ for (scalar @fibs .. $n) {
+ ($nm2, $nm1) = ($nm1, $nm2 + $nm1);
+ push @fibs, $nm1;
+ }
+ }
+ return $fibs[$n];
+ }
+}
+
+# Return all Lucas primes between start and end, using identity:
+# L_n = F_n-1 + F_n+1
+sub lucas_primes {
+ my ($start, $end) = @_;
+ my @lprimes;
+ my $prime = 2;
+ my $k = 0;
+ while ($prime < $start) {
+ $k++;
+ $prime = fib($k) + fib($k+2);
+ }
+ while ($prime <= $end) {
+ push @lprimes, $prime if is_prime($prime);
+ $k++;
+ $prime = fib($k) + fib($k+2);
+ }
+ @lprimes;
+}
+
+sub fibonacci_primes {
+ my ($start, $end) = @_;
+ my @fprimes;
+ my $prime = 2;
+ my $k = 3;
+ while ($prime < $start) {
+ $k++;
+ $prime = fib($k);
+ }
+ while ($prime <= $end) {
+ push @fprimes, $prime if is_prime($prime);
+ # For all but k=4, F_k is prime only when k is prime.
+ $k = ($k <= 4) ? $k+1 : next_prime($k);
+ $prime = fib($k);
+ }
+ @fprimes;
+}
+
+
+my @p;
while ($start <= $end) {
- # small segment size if we're doing bigints
- $segment_size = 10000 if $start > ~0;
+ # This will need to be made more generic if we add more options like this.
+ # FIXME: It also doesn't work for our twin prime selection.
+ if ($show_lucas && $show_fibonacci) {
+ my %l;
+ undef @l{ lucas_primes($start, $end) };
+ @p = grep { exists $l{$_} } fibonacci_primes($start, $end);
+ $start = $end+1;
+
+ } elsif ($show_lucas) {
+ @p = lucas_primes($start, $end);
+ $start = $end+1;
+
+ } elsif ($show_fibonacci) {
+ @p = fibonacci_primes($start, $end);
+ $start = $end+1;
+
+ } else {
+ # small segment size if we're doing bigints
+ $segment_size = 10000 if $start > ~0;
+
+ if ( $show_palindromic && $start >= 100 && (length($start) % 2) == 0 ) {
+ # anything with an even number of digits is divisible by 11
+ $start = 10 ** (length($start)) + 1;
+ }
- my $seg_start = $start;
- my $seg_end = $start + $segment_size;
- $seg_end = $end if $end < $seg_end;
- $start = $seg_end+1;
+ my $seg_start = $start;
+ my $seg_end = $start + $segment_size;
+ $seg_end = $end if $end < $seg_end;
+ $start = $seg_end+1;
+ # Skip ranges where there are no palindromic primes.
+ # - anything starting with 24568 won't be a prime when reversed
+ if ( $show_palindromic && $seg_start >= 100 &&
+ length($seg_start) == length($seg_end)) {
+ next if $seg_start =~ /^2/ && $seg_end =~ /^2/;
+ next if $seg_start =~ /^8/ && $seg_end =~ /^8/;
+ next if $seg_start =~ /^[456]/ && $seg_end =~ /^[456]/;
+ }
+ @p = @{primes($seg_start, $seg_end)};
+ #warn "-- ", scalar @p, " primes between $start and $seg_end\n";
+ }
- # Get a list of all primes in the segment.
- my @p = @{primes($seg_start, $seg_end)};
- #warn "-- ", scalar @p, " primes between $start and $segment_end\n";
next unless scalar @p > 0;
@@ -64,35 +163,52 @@ while ($start <= $end) {
#warn " reduced to ", scalar @p, " twin primes\n";
}
-
# Restrict to safe primes if requested.
if ($show_safe) {
- @p = grep { is_prime( ($_-1) >> 1 ); } @p;
+ @p = grep { is_prime( ($_-1) >> 1 ); }
+ grep { ($_ <= 7) || ($_ % 12) == 11; } # Optimization
+ @p;
#warn " reduced to ", scalar @p, " safe primes\n";
}
-
# Restrict to Sophie Germain primes if requested.
if ($show_sophie) {
- @p = grep { is_prime( 2*$_+1 ); } @p;
+ @p = grep { is_prime( 2*$_+1 ); }
+ grep { my $m30 = $_ % 30;
+ $_ <= 5 || $m30 == 11 || $m30 == 23 || $m30 == 29 ; }
+ @p;
#warn " reduced to ", scalar @p, " SG primes\n";
}
+ # Restrict to Palendromic primes if requested.
+ if ($show_palindromic) {
+ @p = grep { $_ eq reverse $_; } @p;
+ #warn " reduced to ", scalar @p, " Palindromic primes\n";
+ }
+
# print this segment
print join("\n", @p), "\n" if scalar @p > 0;
}
+
+
+
sub die_usage {
die <<EOU;
Usage: $0 [options] START END
Displays all primes between the positive integers START and END, inclusive.
+The START and END values must be integers, however the shortcut "x**y" may
+be used, which allows very large values (e.g. '10**500' or '2**64')
Options:
--help displays this help message
- --safe displays only safe primes, where (p-1)/2 is also prime
--twin displays only twin primes, where p+2 is also prime
+ --safe displays only safe primes, where (p-1)/2 is also prime
--sophie displays only Sophie Germain primes, where 2p+1 is also prime
+ --lucas displays only Lucas primes, where L_n is prime
+ --fibonacci displays only Fibonacci primes, where F_n is prime
+ --palindr displays only Palindromic primes, where p eq reverse p
Note that options can be combined, e.g. display all safe twin primes.
EOU
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libmath-prime-util-perl.git
More information about the Pkg-perl-cvs-commits
mailing list