[libmath-prime-util-perl] 47/50: Have nth_prime use Lehmer prime count on lower bound. 100x speedup for big numbers.

Partha P. Mukherjee ppm-guest at moszumanska.debian.org
Thu May 21 18:45:40 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 9e13087df19c0dd0b64ef94c3e9ed45cad6b6a8a
Author: Dana Jacobsen <dana at acm.org>
Date:   Sun Nov 18 02:42:52 2012 -0800

    Have nth_prime use Lehmer prime count on lower bound.  100x speedup for big numbers.
---
 Changes                    |  4 ++++
 TODO                       |  2 ++
 examples/bench-nthprime.pl |  4 ++--
 t/14-nthprime.t            |  2 +-
 util.c                     | 34 +++++++++++++++++++++++-----------
 5 files changed, 32 insertions(+), 14 deletions(-)

diff --git a/Changes b/Changes
index 3a29363..b6debc8 100644
--- a/Changes
+++ b/Changes
@@ -34,6 +34,10 @@ Revision history for Perl extension Math::Prime::Util.
     - prime_count will use Lehmer prime counting algorithm for largish
       sizes (above 4 million).  This is MUCH faster than sieving.
 
+    - nth_prime now uses the fast Lehmer prime count below the lower limit,
+      then sieves up from there.  This makes a big speed difference for inputs
+      over 10^6 or so -- over 100x faster for 10^9 and up.
+
 0.11  23 July 2012
     - Turn off threading tests on Cygwin, as threads on some Cygwin platforms
       give random panics (my Win7 64-bit works fine, XP 32-bit does not).
diff --git a/TODO b/TODO
index 7da582a..c704281 100644
--- a/TODO
+++ b/TODO
@@ -33,3 +33,5 @@
 - Add Lehmer in PP (I have a version, just needs some polishing).
 
 - Move AKS tests into their own test, and add some provable prime tests.
+
+- Add a 'verbose' option to general config.
diff --git a/examples/bench-nthprime.pl b/examples/bench-nthprime.pl
index 9d5742a..7656b95 100755
--- a/examples/bench-nthprime.pl
+++ b/examples/bench-nthprime.pl
@@ -11,10 +11,10 @@ my $count = shift || -5;
 
 srand(29);
 my @darray;
-push @darray, [gendigits($_,int(2700/($_*$_*$_)))]  for (2 .. 9);
+push @darray, [gendigits($_,int(5400/($_*$_*$_)))]  for (2 .. 10);
 
 my $sum;
-foreach my $digits (3 .. 9) {
+foreach my $digits (3 .. 10) {
   my @digarray = @{$darray[$digits-2]};
   my $numitems = scalar @digarray;
   my $timing = cmpthese(
diff --git a/t/14-nthprime.t b/t/14-nthprime.t
index 6979b9d..c4d3a9d 100644
--- a/t/14-nthprime.t
+++ b/t/14-nthprime.t
@@ -47,7 +47,7 @@ my %nthprimes64 = (
  100000000000000000 => 4185296581467695669,
 );
 my %nthprimes_small = map { $_ => $nthprimes32{$_} }
-                      grep { ($_ <= 2000000) || $extra }
+                      #grep { ($_ <= 2000000) || $extra }
                       keys %nthprimes32;
 
 my @small_primes = (0, @{primes($nth_small_prime)});
diff --git a/util.c b/util.c
index d6aa254..979fe51 100644
--- a/util.c
+++ b/util.c
@@ -31,6 +31,7 @@ extern long double fabsl(long double);
 #include "sieve.h"
 #include "factor.h"
 #include "cache.h"
+#include "lehmer.h"
 
 static const unsigned char byte_zeros[256] =
   {8,7,7,6,7,6,6,5,7,6,6,5,6,5,5,4,7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3,
@@ -555,20 +556,31 @@ UV _XS_nth_prime(UV n)
   upper_limit = _XS_nth_prime_upper(n);
   MPUassert(upper_limit > 0, "nth_prime got an upper limit of 0");
 
-  /* Get the primary cache, and ensure it is at least this large.  If the
-   * input is small enough, get a sieve covering the range.  Otherwise, we'll
-   * walk segments.  Make sure we have enough primes in the cache so the
-   * segmented siever won't have to keep resieving.
+  /* For relatively small values, generate a sieve and count the results.
+   * For larger values, compute a lower bound, use Lehmer's algorithm to get
+   * a fast prime count, then start segment sieving from there.
    */
-  if (upper_limit <= (1*1024*1024*30))
+  if (upper_limit <= 1*1024*1024*30) {
+    /* Generate a sieve and count. */
     segment_size = get_prime_cache(upper_limit, &cache_sieve) / 30;
-  else
-    segment_size = get_prime_cache(sqrt(upper_limit), &cache_sieve) / 30;
+    /* Count up everything in the cached sieve. */
+    if (segment_size > 0)
+      count += count_segment_maxcount(cache_sieve, segment_size, target, &p);
+    release_prime_cache(cache_sieve);
+  } else {
+    double fn = n;
+    double flogn = log(fn);
+    double flog2n = log(flogn);   /* Dusart 2010, page 2, n >= 3 */
+    UV lower_limit = fn * (flogn + flog2n - 1.0 + ((flog2n-2.10)/flogn));
+    segment_size = lower_limit / 30;
+    lower_limit = 30 * segment_size - 1;
+    count = _XS_lehmer_pi(lower_limit) - 3;
+    MPUassert(count <= target, "Pi(nth_prime_lower(n))) > n");
+
+    /* Make sure the segment siever won't have to keep resieving. */
+    prime_precalc(sqrt(upper_limit));
+  }
 
-  /* Count up everything in the cached sieve. */
-  if (segment_size > 0)
-    count += count_segment_maxcount(cache_sieve, segment_size, target, &p);
-  release_prime_cache(cache_sieve);
   if (count == target)
     return p;
 

-- 
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