[libmath-prime-util-perl] 174/181: Move jordan_totient to XS->PP from Util

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 b57e1907eeb7fc524d4da8519f9a38ef2cd3328f
Author: Dana Jacobsen <dana at acm.org>
Date:   Mon Jan 13 13:15:34 2014 -0800

    Move jordan_totient to XS->PP from Util
---
 XS.xs                     | 16 ++++++++++++----
 lib/Math/Prime/Util.pm    | 35 +----------------------------------
 lib/Math/Prime/Util/PP.pm | 23 +++++++++++++++++++++++
 t/80-pp.t                 |  1 +
 util.c                    | 28 ++++++++++++++++++++++++++++
 util.h                    |  1 +
 6 files changed, 66 insertions(+), 38 deletions(-)

diff --git a/XS.xs b/XS.xs
index d1ba176..cdf80e6 100644
--- a/XS.xs
+++ b/XS.xs
@@ -691,7 +691,8 @@ divisor_sum(IN SV* svn, ...)
 void
 znorder(IN SV* sva, IN SV* svn)
   ALIAS:
-    legendre_phi = 1
+    jordan_totient = 1
+    legendre_phi = 2
   PREINIT:
     int astatus, nstatus;
   PPCODE:
@@ -705,14 +706,21 @@ znorder(IN SV* sva, IN SV* svn)
         case 0:  ret = znorder(a, n);
                  if (ret == 0) XSRETURN_UNDEF;  /* not defined */
                  break;
-        case 1:
-        default: ret = legendre_phi(a, n); break;
+        case 1:  ret = jordan_totient(a, n);
+                 if (ret == 0 && n > 1)
+                   goto overflow;
+                 break;
+        case 2:
+        default: ret = legendre_phi(a, n);
+                 break;
       }
       XSRETURN_UV(ret);
     }
+    overflow:
     switch (ix) {
       case 0:  _vcallsub_with_pp("znorder");  break;
-      case 1:
+      case 1:  _vcallsub_with_pp("jordan_totient");  break;
+      case 2:
       default: _vcallsub_with_pp("legendre_phi"); break;
     }
     return; /* skip implicit PUTBACK */
diff --git a/lib/Math/Prime/Util.pm b/lib/Math/Prime/Util.pm
index 6b0217c..4ff112a 100644
--- a/lib/Math/Prime/Util.pm
+++ b/lib/Math/Prime/Util.pm
@@ -116,6 +116,7 @@ BEGIN {
     *prev_prime    = \&Math::Prime::Util::_generic_prev_prime;
     *exp_mangoldt  = \&Math::Prime::Util::_generic_exp_mangoldt;
     *euler_phi     = \&Math::Prime::Util::_generic_euler_phi;
+    *jordan_totient= \&Math::Prime::Util::PP::jordan_totient;
     *moebius       = \&Math::Prime::Util::_generic_moebius;
     *mertens       = \&Math::Prime::Util::_generic_mertens;
     *prime_count   = \&Math::Prime::Util::_generic_prime_count;
@@ -1317,40 +1318,6 @@ sub _generic_euler_phi {
   return Math::Prime::Util::PP::euler_phi_range($n, $nend);
 }
 
-# Jordan's totient -- a generalization of Euler's totient.
-sub jordan_totient {
-  my($k, $n) = @_;
-  _validate_num($k, 1) || _validate_positive_integer($k, 1);
-  return euler_phi($n) if $k == 1;
-
-  return 0 if defined $n && $n <= 0;  # Following SAGE's logic here.
-  _validate_num($n) || _validate_positive_integer($n);
-  return 1 if $n <= 1;
-
-  my @pe = factor_exp($n);
-
-  $n = Math::BigInt->new("$n") if ref($_[1]) eq 'Math::BigInt';
-  my $totient = $n - $n + 1;
-
-  if (ref($n) ne 'Math::BigInt') {
-    foreach my $f (@pe) {
-      my ($p, $e) = @$f;
-      my $fmult = int($p ** $k);
-      $totient *= ($fmult - 1);
-      $totient *= $fmult for (2 .. $e);
-    }
-  } else {
-    my $zero = $n->copy->bzero;
-    foreach my $f (@pe) {
-      my ($p, $e) = @$f;
-      my $fmult = $zero->copy->badd("$p")->bpow($k);
-      $totient->bmul($fmult->copy->bdec());
-      $totient->bmul($fmult) for (2 .. $e);
-    }
-  }
-  return $totient;
-}
-
 sub _generic_divisor_sum {
   my($n) = @_;
   _validate_num($n) || _validate_positive_integer($n);
diff --git a/lib/Math/Prime/Util/PP.pm b/lib/Math/Prime/Util/PP.pm
index ca8fbbb..e9a7d59 100644
--- a/lib/Math/Prime/Util/PP.pm
+++ b/lib/Math/Prime/Util/PP.pm
@@ -494,6 +494,29 @@ sub prev_prime {
   #$d*30+$m;
 }
 
+sub jordan_totient {
+  my($k, $n) = @_;
+  _validate_num($k) || _validate_positive_integer($k);
+  return ($n == 1) ? 1 : 0  if $k == 0;
+  return euler_phi($n)      if $k == 1;
+  return 0 if defined $n && $n < 0;  # Following SAGE's logic here.
+  _validate_num($n) || _validate_positive_integer($n);
+  return ($n == 1) ? 1 : 0  if $n <= 1;
+
+  my @pe = Math::Prime::Util::factor_exp($n);
+  $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt';
+  my $totient = BONE->copy;
+  foreach my $f (@pe) {
+    my ($p, $e) = @$f;
+    $p = Math::BigInt->new("$p") unless ref($p) eq 'Math::BigInt';
+    $p->bpow($k);
+    $totient->bmul($p->copy->bdec());
+    $totient->bmul($p) for 2 .. $e;
+  }
+  $totient = _bigint_to_int($totient) if $totient->bacmp(''.~0) <= 0;
+  return $totient;
+}
+  
 sub euler_phi {
   my($n) = @_;
   return 0 if $n < 0;
diff --git a/t/80-pp.t b/t/80-pp.t
index 2240202..d88d550 100644
--- a/t/80-pp.t
+++ b/t/80-pp.t
@@ -602,6 +602,7 @@ is( is_aks_prime(23), 1, "AKS: 23 is prime (r >= n)" );
 is( is_aks_prime(70747), 0, "AKS: 70747 is composite (n mod r)" );
 SKIP: {
   skip "Skipping PP AKS test without EXTENDED_TESTING", 2 unless $extra;
+  diag "32-bit Perl will be very slow for AKS" unless $use64;
   is( is_aks_prime(101), 1, "AKS: 101 is prime (passed anr test)" );
   is( is_aks_prime(74513), 0, "AKS: 74513 is composite (failed anr test)" );
 }
diff --git a/util.c b/util.c
index 8480572..dcf76a2 100644
--- a/util.c
+++ b/util.c
@@ -918,6 +918,34 @@ UV totient(UV n) {
   return totient;
 }
 
+static const UV jordan_overflow[5] =
+#if BITS_PER_WORD == 64
+  {UVCONST(4294967311), 2642249, 65537, 7133, 1627};
+#else
+  {UVCONST(     65537),    1627,   257,   85,   41};
+#endif
+UV jordan_totient(UV k, UV n) {
+  UV factors[MPU_MAX_FACTORS+1];
+  int nfac, i, j;
+  UV totient;
+  if (k == 0 || n <= 1) return (n == 1);
+  if (k > 6 || (k > 1 && n >= jordan_overflow[k-2])) return 0;
+
+  totient = 1;
+  nfac = factor(n,factors);
+  for (i = 0; i < nfac; i++) {
+    UV p = factors[i];
+    UV pk = p;
+    for (j = 1; j < k; j++)  pk *= p;
+    totient *= (pk-1);
+    while (i+1 < nfac && p == factors[i+1]) {
+      i++;
+      totient *= pk;
+    }
+  }
+  return totient;
+}
+
 UV carmichael_lambda(UV n) {
   UV fac[MPU_MAX_FACTORS+1];
   UV exp[MPU_MAX_FACTORS+1];
diff --git a/util.h b/util.h
index 8627110..715e4b7 100644
--- a/util.h
+++ b/util.h
@@ -37,6 +37,7 @@ extern UV totient(UV n);
 extern int moebius(UV n);
 extern UV exp_mangoldt(UV n);
 extern UV carmichael_lambda(UV n);
+extern UV jordan_totient(UV k, UV n);
 extern UV znprimroot(UV n);
 extern UV znorder(UV a, UV n);
 extern UV znlog(UV a, UV g, UV 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