[libmath-prime-util-perl] 166/181: ranged totient faster and uses less memory

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


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

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

commit 99ae3044841e270f8519c0519d381450faf010be
Author: Dana Jacobsen <dana at acm.org>
Date:   Sun Jan 12 03:19:44 2014 -0800

    ranged totient faster and uses less memory
---
 util.c | 44 +++++++++++++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 13 deletions(-)

diff --git a/util.c b/util.c
index 0a51199..ec16748 100644
--- a/util.c
+++ b/util.c
@@ -790,10 +790,20 @@ signed char* _moebius_range(UV lo, UV hi)
 
 UV* _totient_range(UV lo, UV hi) {
   UV* totients;
-  UV i;
+  UV i, seg_base, seg_low, seg_high;
+  unsigned char* segment;
+  void* ctx;
+
   if (hi < lo) croak("_totient_range error hi %lu < lo %lu\n", hi, lo);
-  /* TODO: When is it faster to just do individual calls? */
   New(0, totients, hi-lo+1, UV);
+
+  /* Do via factoring if very small or if we have a small range */
+  if (hi < 100 || hi/(hi-lo+1) > 1000) {
+    for (i = lo; i <= hi; i++)
+      totients[i-lo] = totient(i);
+    return totients;
+  }
+
   for (i = lo; i <= hi; i++) {
     UV v = i;
     if (i % 2 == 0)  v -= v/2;
@@ -801,13 +811,22 @@ UV* _totient_range(UV lo, UV hi) {
     if (i % 5 == 0)  v -= v/5;
     totients[i-lo] = v;
   }
-  START_DO_FOR_EACH_PRIME(lo, hi) {
-    totients[p-lo] = p-1;
-  } END_DO_FOR_EACH_PRIME
-  START_DO_FOR_EACH_PRIME(7, hi/2) {
-    for (i = P2GTLO(2*p,p,lo); i <= hi; i += p)
-      totients[i-lo] -= totients[i-lo]/p;
-  } END_DO_FOR_EACH_PRIME
+
+  ctx = start_segment_primes(7, hi/2, &segment);
+  while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
+    START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_low - seg_base, seg_high - seg_base ) {
+      p += seg_base;
+      for (i = P2GTLO(2*p,p,lo); i <= hi; i += p)
+        totients[i-lo] -= totients[i-lo]/p;
+    } END_DO_FOR_EACH_SIEVE_PRIME
+  }
+  end_segment_primes(ctx);
+
+  /* Fill in all primes */
+  for (i = lo | 1; i <= hi; i += 2)
+    if (totients[i-lo] == i)
+      totients[i-lo]--;
+
   return totients;
 }
 
@@ -930,7 +949,7 @@ UV carmichael_lambda(UV n) {
   UV j, lambda = 1;
 
   if (n < 8) return totient(n);
-  if ((n & (n-1)) == 0)  return totient(n)/2;
+  if ((n & (n-1)) == 0) return n >> 2;
 
   nfactors = factor_exp(n, fac, exp);
   if (fac[0] == 2 && exp[0] > 2)  exp[0]--;
@@ -946,10 +965,9 @@ UV carmichael_lambda(UV n) {
 int moebius(UV n) {
   UV factors[MPU_MAX_FACTORS+1];
   UV i, nfactors;
-  if (n <= 1) return (int)n;
 
-  if ( (!(n% 4) && n >=  4) || (!(n% 9) && n >=  9) ||
-       (!(n%25) && n >= 25) || (!(n%49) && n >= 49) )
+  if (n <= 1) return (int)n;
+  if ( n >= 49 && (!(n% 4) || !(n% 9) || !(n%25) || !(n%49)) )
     return 0;
 
   nfactors = factor(n, factors);

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