[libmath-prime-util-perl] 15/20: Move totient range to util.c, speed it up a little bit

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 4af68950730378cac15f16f221289ec81146b70e
Author: Dana Jacobsen <dana at acm.org>
Date:   Mon Mar 4 05:25:35 2013 -0800

    Move totient range to util.c, speed it up a little bit
---
 XS.xs  | 39 ++++++++++++---------------------------
 util.c | 32 +++++++++++++++++++++++++++++++-
 util.h |  1 +
 3 files changed, 44 insertions(+), 28 deletions(-)

diff --git a/XS.xs b/XS.xs
index bd60751..af95cde 100644
--- a/XS.xs
+++ b/XS.xs
@@ -359,46 +359,31 @@ _XS_RiemannR(double x)
 
 void
 _XS_totient(IN UV lo, IN UV hi = 0)
+  PREINIT:
+    UV i;
   PPCODE:
-    if (hi != lo && hi != 0) {
-      /* Totients in a range, returns array */
+    if (hi != lo && hi != 0) { /* Totients in a range, returns array */
       UV* totients;
-      UV i, p;
-
       if (hi < lo) XSRETURN_EMPTY;
       if (lo < 2) {
         if (lo <= 0           ) XPUSHs(sv_2mortal(newSVuv(0)));
         if (lo <= 1 && hi >= 1) XPUSHs(sv_2mortal(newSVuv(1)));
         lo = 2;
       }
-      New(0, totients, hi-lo+1, UV);
-      if (totients == 0)
-        croak("Could not get memory for %"UVuf" totients\n", hi);
-      for (i = lo; i <= hi; i++)
-        totients[i-lo] = i;
-      prime_precalc( hi/2 );
-      for (p = 2; p <= hi/2; p = _XS_next_prime(p)) {
-        i = 2*p;
-        if (i < lo)  i = p*(lo/p) + ( (lo%p) ? p : 0 );
-        for ( ; i <= hi; i += p)
-          totients[i-lo] -= totients[i-lo]/p;
+      if (hi >= lo) {
+        totients = _totient_range(lo, hi);
+        /* Extend the stack to handle how many items we'll return */
+        EXTEND(SP, hi-lo+1);
+        for (i = lo; i <= hi; i++)
+          PUSHs(sv_2mortal(newSVuv(totients[i-lo])));
+        Safefree(totients);
       }
-      /* Extend the stack to handle how many items we'll return */
-      EXTEND(SP, hi-lo+1);
-      for (i = lo; i <= hi; i++) {
-        UV t = totients[i-lo];
-        if (t == i)
-          t = i-1;
-        PUSHs(sv_2mortal(newSVuv(t)));
-      }
-      Safefree(totients);
-
     } else {
       UV facs[MPU_MAX_FACTORS+1];  /* maximum number of factors is log2n */
-      UV i, nfacs, totient, lastf;
+      UV nfacs, totient, lastf;
       UV n = lo;
       if (n <= 1) XSRETURN_UV(n);
-      nfacs = trial_factor(n, facs, 0);
+      nfacs = factor(n, facs);
       totient = 1;
       lastf = 0;
       for (i = 0; i < nfacs; i++) {
diff --git a/util.c b/util.c
index 66525c1..1da3426 100644
--- a/util.c
+++ b/util.c
@@ -651,7 +651,7 @@ 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. */
-#define PGTLO(p,lo)  (p >= lo) ? p : (p*(lo/p) + ((lo%p)?p:0))
+#define PGTLO(p,lo)  ((p) >= lo) ? (p) : ((p)*(lo/(p)) + ((lo%(p))?(p):0))
 char* _moebius_range(UV lo, UV hi)
 {
   char* mu;
@@ -746,6 +746,36 @@ char* _moebius_range(UV lo, UV hi)
   return mu;
 }
 
+UV* _totient_range(UV lo, UV hi) {
+  UV* totients;
+  const unsigned char* sieve;
+  UV i, sievehi;
+  if (hi < lo) croak("_totient_range error hi %lu < lo %lu\n", hi, lo);
+  New(0, totients, hi-lo+1, UV);
+  if (totients == 0)
+    croak("Could not get memory for %"UVuf" totients\n", hi);
+  for (i = lo; i <= hi; i++)
+    totients[i-lo] = i;
+  for (i = PGTLO(2*2, lo); i <= hi; i += 2) totients[i-lo] -= totients[i-lo]/2;
+  for (i = PGTLO(2*3, lo); i <= hi; i += 3) totients[i-lo] -= totients[i-lo]/3;
+  for (i = PGTLO(2*5, lo); i <= hi; i += 5) totients[i-lo] -= totients[i-lo]/5;
+  sievehi = hi/2;
+  if (get_prime_cache(sievehi, &sieve) < sievehi) {
+    release_prime_cache(sieve);
+    croak("Could not generate sieve for %"UVuf, sievehi);
+  } else {
+    START_DO_FOR_EACH_SIEVE_PRIME( sieve, 7, sievehi ) {
+      for (i = PGTLO(2*p, lo); i <= hi; i += p)
+        totients[i-lo] -= totients[i-lo]/p;
+    } END_DO_FOR_EACH_SIEVE_PRIME
+    release_prime_cache(sieve);
+  }
+  for (i = lo; i <= hi; i++)
+    if (totients[i-lo] == i)
+      totients[i-lo] = i-1;
+  return totients;
+}
+
 IV _XS_mertens(UV n) {
 #if 0
   /* Benito and Varona 2008, theorem 3.  Segment. */
diff --git a/util.h b/util.h
index a7b56e4..a2d7f7c 100644
--- a/util.h
+++ b/util.h
@@ -15,6 +15,7 @@ extern UV  _XS_prime_count(UV low, UV high);
 extern UV  _XS_nth_prime(UV x);
 
 extern char*  _moebius_range(UV low, UV high);
+extern UV*    _totient_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