[libmath-prime-util-perl] 14/20: Change type of mobius return. Some different ranged algorithms in comments

Partha P. Mukherjee ppm-guest at moszumanska.debian.org
Thu May 21 18:47:32 UTC 2015


This is an automated email from the git hooks/post-receive script.

ppm-guest pushed a commit to annotated tag v0.23
in repository libmath-prime-util-perl.

commit 7be91a6ad6e358ec9de02359c8c50397855e8f2e
Author: Dana Jacobsen <dana at acm.org>
Date:   Sun Mar 3 18:19:53 2013 -0800

    Change type of mobius return.  Some different ranged algorithms in comments
---
 XS.xs  |   2 +-
 util.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++-----------------
 util.h |   4 +--
 3 files changed, 83 insertions(+), 31 deletions(-)

diff --git a/XS.xs b/XS.xs
index 8892164..bd60751 100644
--- a/XS.xs
+++ b/XS.xs
@@ -415,7 +415,7 @@ _XS_moebius(IN UV lo, IN UV hi = 0)
     UV i;
   PPCODE:
     if (hi != lo && hi != 0) {   /* mobius in a range */
-      IV* mu = _moebius_range(lo, hi);
+      char* mu = _moebius_range(lo, hi);
       MPUassert( mu != 0, "_moebius_range returned 0" );
       EXTEND(SP, hi-lo+1);
       for (i = lo; i <= hi; i++)
diff --git a/util.c b/util.c
index b041fb6..66525c1 100644
--- a/util.c
+++ b/util.c
@@ -651,46 +651,98 @@ UV _XS_nth_prime(UV n)
 
 /* Return an IV array with lo-hi+1 elements.  mu[k-lo] = µ(k) for k = lo .. hi.
  * It is the callers responsibility to call Safefree on the result. */
-IV* _moebius_range(UV lo, UV hi)
+#define PGTLO(p,lo)  (p >= lo) ? p : (p*(lo/p) + ((lo%p)?p:0))
+char* _moebius_range(UV lo, UV hi)
 {
-  IV* mu;
-  UV i, p, sqrtn;
+  char* mu;
+  UV i, p;
+  UV sqrtn = isqrt(hi);
+#if 1
+  IV* A;
 
   /* This implementation follows that of Deléglise & Rivat (1996), which is
-   * a segmented version of Lioen & van de Lune (1994).
+   * a segmented version of Lioen & van de Lune (1994).  Downside is that it
+   * uses an array of IV's, so too much memory.  Pawleicz (2011) shows a small
+   * variation but seems to just be a rearrangement -- there is no time or
+   * space difference on my machines. (TODO: but maybe for hi > 2^63?)
    */
-  sqrtn = isqrt(hi);
 
-  New(0, mu, hi-lo+1, IV);
-  if (mu == 0)
+  New(0, A, hi-lo+1, IV);
+  if (A == 0)
     croak("Could not get memory for %"UVuf" moebius results\n", hi-lo+1);
   for (i = lo; i <= hi; i++)
-    mu[i-lo] = 1;
-  if (lo == 0)  mu[0] = 0;
+    A[i-lo] = 1;
   prime_precalc(sqrtn);
   for (p = 2; p <= sqrtn; p = _XS_next_prime(p)) {
-    i = p*p;
-    if (i < lo)
-      i = i*(lo/i) + ( (lo%i) ? i : 0 );
-    while (i <= hi) {
+    UV p2 = p*p;
+    for (i = PGTLO(p2, lo); i <= hi; i += p2)
+      A[i-lo] = 0;
+    for (i = PGTLO(p, lo); i <= hi; i += p)
+      A[i-lo] *= -(IV)p;
+  }
+  New(0, mu, hi-lo+1, char);
+  if (mu == 0)
+    croak("Could not get memory for %"UVuf" moebius results\n", hi-lo+1);
+  memset(mu, 0, hi-lo+1);
+  for (i = lo; i <= hi; i++) {
+    IV a = A[i-lo];
+    if (a != 0)
+      mu[i-lo] = (a != i && -a != i)  ?  (a<0) - (a>0)
+                                      :  (a>0) - (a<0);
+  }
+  Safefree(A);
+#endif
+#if 0
+  /* Simple char method, Needs way too many primes */
+  New(0, mu, hi-lo+1, char);
+  if (mu == 0)
+    croak("Could not get memory for %"UVuf" moebius results\n", hi-lo+1);
+  memset(mu, 1, hi-lo+1);
+  if (lo == 0)  mu[0] = 0;
+  prime_precalc( _XS_nth_prime_upper(hi) );
+  for (p = 2; p <= hi; p = _XS_next_prime(p)) {
+    UV p2 = p*p;
+    for (i = PGTLO(p2, lo); i <= hi; i += p2)
       mu[i-lo] = 0;
-      i += p*p;
-    }
-    i = p;
-    if (i < lo)
-      i = i*(lo/i) + ( (lo%i) ? i : 0 );
-    while (i <= hi) {
-      mu[i-lo] *= -(IV)p;
-      i += p;
-    }
+    for (i = PGTLO(p, lo); i <= hi; i += p)
+      mu[i-lo] = -mu[i-lo];
   }
+#endif
+#if 0
+  /* Kuznetsov's transform of Deléglise & Rivat (1996) into logs.
+   * (1) I'm using the log function, which should be fixed (easy).
+   * (2) it doesn't work.  try 64-101 vs. 64 vs. 100.
+   */
+  unsigned char* A;
+  New(0, A, hi-lo+1, unsigned char);
+  if (A == 0)
+    croak("Could not get memory for %"UVuf" moebius results\n", hi-lo+1);
+  memset(A, 0, hi-lo+1);
+  if (sqrtn*sqrtn != hi) sqrtn++;  /* ceil sqrtn */
+  prime_precalc(sqrtn);
+  for (p = 2; p <= sqrtn; p = _XS_next_prime(p)) {
+    UV p2 = p*p;
+    unsigned char l = 1 | (unsigned char) ( log(p)/log(2) );
+    for (i = PGTLO(p, lo); i <= hi; i += p)
+      A[i-lo] += l;
+    for (i = PGTLO(p2, lo); i <= hi; i += p2)
+      A[i-lo] |= 0x80;
+  }
+
+  New(0, mu, hi-lo+1, char);
+  if (mu == 0)
+    croak("Could not get memory for %"UVuf" moebius results\n", hi-lo+1);
   for (i = lo; i <= hi; i++) {
-    IV m = mu[i-lo];
-    if (m != 0) {
-      if (m != i && -m != i)  m *= -1;
-      mu[i-lo] = (m>0) - (m<0);
-    }
+    unsigned char a = A[i-lo];
+    unsigned char log2i = (unsigned char) ( log(i)/log(2) );
+    //printf("i = %lu  a = %lu  log2i = %lu\n", i, a, log2i);
+    if (a & 0x80) { mu[i-lo] = 0; }
+    else if (a >= log2i) { mu[i-lo] =  1 - 2*(a&1); }
+    else                 { mu[i-lo] = -1 + 2*(a&1); }
   }
+  if (lo == 0)  mu[0] = 0;
+  Safefree(A);
+#endif
   return mu;
 }
 
@@ -720,7 +772,7 @@ IV _XS_mertens(UV n) {
   /* Deléglise and Rivat (1996) using u = n^1/2 and unsegmented. */
   /* Very simple, but they use u = n^1/3 and segment */
   UV u, i, m, nmk;
-  IV* mu;
+  char* mu;
   IV* M;
   IV sum;
 
diff --git a/util.h b/util.h
index 9d9821e..a7b56e4 100644
--- a/util.h
+++ b/util.h
@@ -14,8 +14,8 @@ extern UV  _XS_prev_prime(UV x);
 extern UV  _XS_prime_count(UV low, UV high);
 extern UV  _XS_nth_prime(UV x);
 
-extern IV* _moebius_range(UV low, UV high);
-extern IV  _XS_mertens(UV n);
+extern char*  _moebius_range(UV low, UV high);
+extern IV     _XS_mertens(UV n);
 extern double _XS_chebyshev_theta(UV n);
 extern double _XS_chebyshev_psi(UV n);
 

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