[libmath-prime-util-perl] 25/33: Update some examples
Partha P. Mukherjee
ppm-guest at moszumanska.debian.org
Thu May 21 18:51:43 UTC 2015
This is an automated email from the git hooks/post-receive script.
ppm-guest pushed a commit to annotated tag v0.37
in repository libmath-prime-util-perl.
commit 1f31843759f3d21a0ff9926d2bafcf1eae4dfac0
Author: Dana Jacobsen <dana at acm.org>
Date: Fri Jan 24 17:04:58 2014 -0800
Update some examples
---
examples/abundant.pl | 2 +-
examples/sophie_germain.pl | 133 ++++++++++++++++++++++++++++-----------------
examples/twin_primes.pl | 30 ++++++----
3 files changed, 103 insertions(+), 62 deletions(-)
diff --git a/examples/abundant.pl b/examples/abundant.pl
index 23b3564..8cfe2b4 100755
--- a/examples/abundant.pl
+++ b/examples/abundant.pl
@@ -5,7 +5,6 @@ use warnings;
# Find the first N abundant, deficient, or perfect numbers.
use Math::Prime::Util qw/divisor_sum next_prime is_prime/;
-use Math::BigInt try => "GMP,Pari";
my $count = shift || 20;
my $type = lc(shift || 'abundant');
@@ -26,6 +25,7 @@ if ($type eq 'abundant') {
# We just look for 2^(p-1)*(2^p-1) where 2^p-1 is prime.
# Basically we're just finding Mersenne primes.
# It's possible there are odd perfect numbers larger than 10^1500.
+ do { require Math::BigInt; Math::BigInt->import(try=>"GMP,Pari"); };
while ($count-- > 0) {
while (1) {
$p = next_prime($p);
diff --git a/examples/sophie_germain.pl b/examples/sophie_germain.pl
index 0fec4b1..971ad3b 100755
--- a/examples/sophie_germain.pl
+++ b/examples/sophie_germain.pl
@@ -6,59 +6,92 @@ use Math::Prime::Util qw/prime_iterator is_prime
next_prime nth_prime_upper prime_precalc forprimes/;
my $count = shift || 20;
+my $method = shift || 'forprimes';
+my $precalc = 0; # If set, precalc all the values we'll call is_prime on
# Find Sophie Germain primes (numbers where p and 2p+1 are both prime).
-# In this method, we add a filter in front of our iterator, to create a
-# Sophie-Germain-prime iterator. This isn't the fastest way, but it's still
-# 20x faster than Math::NumSeq::SophieGermainPrimes at 300k. If we add the
-# two-line precalc shown below, we can get another 4x or more.
-#
-# Example:
-# time perl examples/sophie_germain.pl 300000 | md5sum
-# d380d31256cc9bc54eb5f236b3edc16d -
-# 9.673s
-#
-# time perl -MMath::NumSeq::SophieGermainPrimes -E 'my $seq = Math::NumSeq::SophieGermainPrimes->new; do { say 0+($seq->next)[1] } for 1..300000' | md5sum
-# d380d31256cc9bc54eb5f236b3edc16d -
-# 4m11.5s
+# Four methods are shown: forprimes, iter, iter2, and MNS.
+
+# Times for 300k:
#
-# With method 2:
-# time perl examples/sophie_germain.pl 300000 | md5sum
-# d380d31256cc9bc54eb5f236b3edc16d -
-# 1.828s
-
-
-sub get_sophie_germain_iterator {
- my $p = shift || 2;
- my $it = prime_iterator($p);
- return sub {
- do { $p = $it->() } while !is_prime(2*$p+1);
- $p;
- };
+# 300k 1M
+# precalc:
+# forprimes 1.3s 9.0MB 7.1s 21.6MB
+# iter 2.8s 8.7MB 12.6s 21.4MB
+# iter2 1.9s 8.7MB 9.4s 21.4MB
+# no precalc:
+# forprimes 1.5s 4.5MB 5.6s 4.5MB
+# iter 9.5s 4.3MB 37.5s 4.3MB
+# iter2 8.5s 4.3MB 33.9s 4.3MB
+# MNS 254.3s 11.3MB >1500s >15 MB
+
+if ($precalc) {
+ prime_precalc(2 * sg_upper_bound($count));
}
-my $sgit = get_sophie_germain_iterator();
-print $sgit->(), "\n" for 1 .. $count;
-# Method 2. At 300k this is 70x faster than Math::NumSeq::SophieGermainPrimes.
-#
-#my $estimate = 100 + int( nth_prime_upper($count) * 1.6 * log($count) );
-#prime_precalc(2 * $estimate);
-#
-#my $prime = 2;
-#for (1..$count) {
-# $prime = next_prime($prime) while (!is_prime(2*$prime+1));
-# print "$prime\n";
-# $prime = next_prime($prime);
-#}
-
-# Alternate method, 10-20% faster, would benefit from a tighter estimate.
-#
-# my $numfound = 0;
-# forprimes {
-# if ($numfound < $count && is_prime(2*$_+1)) {
-# print "$_\n";
-# $numfound++;
-# }
-# } $estimate;
-# die "Estimate too low" unless $numfound >= $count;
+
+if ($method eq 'forprimes') {
+
+ my $estimate = sg_upper_bound($count);
+ my $numfound = 0;
+ forprimes {
+ if ($numfound < $count && is_prime(2*$_+1)) {
+ print "$_\n";
+ $numfound++;
+ }
+ } $estimate;
+ die "Estimate too low" unless $numfound >= $count;
+
+} elsif ($method eq 'iter') {
+
+ # Wrap the standard iterator
+ sub get_sophie_germain_iterator {
+ my $p = shift || 2;
+ my $it = prime_iterator($p);
+ return sub {
+ do { $p = $it->() } while !is_prime(2*$p+1);
+ $p;
+ };
+ }
+ my $sgit = get_sophie_germain_iterator();
+ print $sgit->(), "\n" for 1 .. $count;
+
+} elsif ($method eq 'iter2') {
+
+ # Iterate directly using next_prime
+ my $prime = 2;
+ for (1 .. $count) {
+ $prime = next_prime($prime) while !is_prime(2*$prime+1);
+ print "$prime\n";
+ $prime = next_prime($prime);
+ }
+
+} elsif ($method eq 'MNS') {
+
+ # Use Math::NumSeq
+ require Math::NumSeq::SophieGermainPrimes;
+ my $seq = Math::NumSeq::SophieGermainPrimes->new;
+ for (1 .. $count) {
+ print 0+($seq->next)[1];
+ }
+
+}
+
+# Used for precalc and the forprimes example
+sub sg_upper_bound {
+ my $count = shift;
+ my $nth = nth_prime_upper($count);
+ # For lack of a better formula, do this step-wise estimate.
+ my $estimate = ($count < 5000) ? 150 + int( $nth * log($nth) * 1.2 )
+ : ($count < 19000) ? int( $nth * log($nth) * 1.135 )
+ : ($count < 45000) ? int( $nth * log($nth) * 1.10 )
+ : ($count < 100000) ? int( $nth * log($nth) * 1.08 )
+ : ($count < 165000) ? int( $nth * log($nth) * 1.06 )
+ : ($count < 360000) ? int( $nth * log($nth) * 1.05 )
+ : ($count < 750000) ? int( $nth * log($nth) * 1.04 )
+ : ($count <1700000) ? int( $nth * log($nth) * 1.03 )
+ : int( $nth * log($nth) * 1.02 );
+
+ return $estimate;
+}
diff --git a/examples/twin_primes.pl b/examples/twin_primes.pl
index 362a737..514cc70 100755
--- a/examples/twin_primes.pl
+++ b/examples/twin_primes.pl
@@ -2,8 +2,7 @@
use strict;
use warnings;
-use Math::Prime::Util qw/-nobigint
- prime_iterator prime_iterator_object
+use Math::Prime::Util qw/prime_iterator prime_iterator_object
next_prime is_prime
nth_prime_upper prime_precalc/;
@@ -12,16 +11,25 @@ my $count = shift || 20;
# Find twin primes (numbers where p and p+2 are prime)
# Time for the first 300k:
+#
+# Not iterators:
+# 0.6s forprimes { say $l if $l+2==$_; $l=$_; } 64764841
# 1.0s bin/primes.pl --twin 2 64764839
-# 1.4s get_twin_prime_iterator2
-# 2.3s get_twin_prime_iterator1
-# 4.1s get_twin_prime_iterator3
-# 6.1s get_twin_prime_iterator3 (object iterator)
-# 7.6s get_twin_prime_iterator2 without precalc
-# 8.4s get_twin_prime_iterator1 without precalc
-# 10.9s get_twin_prime_iterator3 without precalc
-# 13.1s get_twin_prime_iterator3 without precalc (object iterator)
-# 219.8s Math::NumSeq::TwinPrimes (Perl 5.19.4 with v66)
+#
+# Iterators with precalc:
+# 1.6s get_twin_prime_iterator2
+# 2.4s get_twin_prime_iterator1
+# 4.2s get_twin_prime_iterator3
+# 4.5s get_twin_prime_iterator4 (object iterator)
+#
+# Iterators without precalc:
+# 7.7s get_twin_prime_iterator2
+# 8.5s get_twin_prime_iterator1
+# 10.8s get_twin_prime_iterator3
+# 16.7s get_twin_prime_iterator4 (object iterator)
+#
+# Alternatives:
+# 251.9s Math::NumSeq::TwinPrimes (Perl 5.19.7, Math::NumSeq 67)
# This speeds things up, but isn't necessary.
my $estimate = 5000 + int( nth_prime_upper($count) * 1.4 * log($count) );
--
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