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 0d7529aa685cbe178fbf9c7f51febdbfc1f5e489
Author: Dana Jacobsen <d...@acm.org>
Date:   Mon Dec 30 01:22:08 2013 -0800

    Shuffle functions between XS/Util/PP; significant XS changes
---
 XS.xs                     | 582 ++++++++++++++++++----------------------------
 lib/Math/Prime/Util.pm    | 120 ++--------
 lib/Math/Prime/Util/PP.pm |  98 ++++++++
 3 files changed, 340 insertions(+), 460 deletions(-)

diff --git a/XS.xs b/XS.xs
index 1576e72..8fa41fc 100644
--- a/XS.xs
+++ b/XS.xs
@@ -68,10 +68,6 @@
 #endif
 
 
-static int pbrent_factor_a1(UV n, UV *factors, UV maxrounds) {
-  return pbrent_factor(n, factors, maxrounds, 1);
-}
-
 #if BITS_PER_WORD == 32
   static const unsigned int uvmax_maxlen = 10;
   static const unsigned int ivmax_maxlen = 10;
@@ -91,12 +87,14 @@ static int pbrent_factor_a1(UV n, UV *factors, UV 
maxrounds) {
  */
 static int _validate_int(SV* n, int negok)
 {
-  dTHX;
+  pTHX_;
   const char* maxstr;
   char* ptr;
   STRLEN i, len, maxlen;
   int ret, isneg = 0;
 
+  /* TODO: magic, grok_number, etc. */
+  if (SvGAMAGIC(n)) return 0;          /* Leave while we still can */
   if (!SvOK(n))  croak("Parameter must be defined");
   if (SvIOK(n)) {                      /* If defined as number, use that */
     if (SvIsUV(n) || SvIV(n) >= 0)  return 1;
@@ -132,38 +130,16 @@ static int _validate_int(SV* n, int negok)
   return ret;                          /* value = UV_MAX/UV_MIN.  That's ok */
 }
 
-/* Call a Perl sub to handle work for us.
- *   The input is a single SV on the top of the stack.
- *   The output is a single mortal SV that is on the stack.
- */
-static void _vcallsub(const char* name)
+/* Call a Perl sub to handle work for us. */
+static int _vcallsubn(I32 flags, const char* name, int nargs)
 {
-  dTHX;
-  dSP;                               /* Local copy of stack pointer         */
-  int count;
-  SV* arg;
-
-  ENTER;                             /* Start wrapper                       */
-  SAVETMPS;                          /* Start (2)                           */
-
-  arg = POPs;                        /* Get argument value from stack       */
-  PUSHMARK(SP);                      /* Start args: note our SP             */
-  XPUSHs(arg);
-  PUTBACK;                           /* End args:   set global SP to ours   */
-
-  count = call_pv(name, G_SCALAR);   /* Call the sub                        */
-  SPAGAIN;                           /* refresh local stack pointer         */
-
-  if (count != 1)
-    croak("callback sub should return one value");
-
-  TOPs = SvREFCNT_inc(TOPs);         /* Make sure FREETMPS doesn't kill it  */
-
-  PUTBACK;
-  FREETMPS;                          /* End wrapper                         */
-  LEAVE;                             /* End (2)                             */
-  TOPs = sv_2mortal(TOPs);           /* mortalize it.  refcnt will be 1.    */
+      pTHX_;
+      dSP;
+      PUSHMARK(SP-nargs);
+      PUTBACK;
+      return call_pv(name, flags);
 }
+#define _vcallsub(func) (void)_vcallsubn(G_SCALAR, func, 1)
 
 #if BITS_PER_WORD == 64
 static const UV _max_prime = UVCONST(18446744073709551557);
@@ -267,37 +243,10 @@ _XS_prime_maxbits()
 
 SV*
 sieve_primes(IN UV low, IN UV high)
-  PREINIT:
-    AV* av = newAV();
-  CODE:
-    if (low <= high) {
-      START_DO_FOR_EACH_PRIME(low, high) {
-        av_push(av,newSVuv(p));
-      } END_DO_FOR_EACH_PRIME
-    }
-    RETVAL = newRV_noinc( (SV*) av );
-  OUTPUT:
-    RETVAL
-
-
-SV*
-trial_primes(IN UV low, IN UV high)
-  PREINIT:
-    UV  p;
-    AV* av = newAV();
-  CODE:
-    if (low <= high) {
-      if (low >= 2) low--;   /* Make sure low gets included */
-      for (p = _XS_next_prime(low); p <= high && p != 0; p = 
_XS_next_prime(p)) {
-        av_push(av,newSVuv(p));
-      }
-    }
-    RETVAL = newRV_noinc( (SV*) av );
-  OUTPUT:
-    RETVAL
-
-SV*
-segment_primes(IN UV low, IN UV high);
+  ALIAS:
+    trial_primes = 1
+    erat_primes = 2
+    segment_primes = 3
   PREINIT:
     AV* av = newAV();
   CODE:
@@ -306,102 +255,39 @@ segment_primes(IN UV low, IN UV high);
     if ((low <= 5) && (high >= 5)) { av_push(av, newSVuv( 5 )); }
     if (low < 7)  low = 7;
     if (low <= high) {
-      unsigned char* segment;
-      UV seg_base, seg_low, seg_high;
-      void* ctx = start_segment_primes(low, high, &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 )
-          av_push(av,newSVuv( seg_base + p ));
-        END_DO_FOR_EACH_SIEVE_PRIME
-      }
-      end_segment_primes(ctx);
-    }
-    RETVAL = newRV_noinc( (SV*) av );
-  OUTPUT:
-    RETVAL
-
-SV*
-erat_primes(IN UV low, IN UV high)
-  PREINIT:
-    unsigned char* sieve;
-    AV* av = newAV();
-  CODE:
-    if (low <= high) {
-      sieve = sieve_erat30(high);
-      if (sieve == 0) {
-        croak("Could not generate sieve for %"UVuf, high);
-      } else {
-        if ((low <= 2) && (high >= 2)) { av_push(av, newSVuv( 2 )); }
-        if ((low <= 3) && (high >= 3)) { av_push(av, newSVuv( 3 )); }
-        if ((low <= 5) && (high >= 5)) { av_push(av, newSVuv( 5 )); }
-        if (low < 7) { low = 7; }
+      if (ix == 0) {                          /* Sieve */
+        START_DO_FOR_EACH_PRIME(low, high) {
+          av_push(av,newSVuv(p));
+        } END_DO_FOR_EACH_PRIME
+      } else if (ix == 1) {                   /* Trial */
+        for (low = _XS_next_prime(low-1);
+             low <= high && low != 0;
+             low = _XS_next_prime(low) ) {
+          av_push(av,newSVuv(low));
+        }
+      } else if (ix == 2) {                   /* Erat */
+        unsigned char* sieve = sieve_erat30(high);
+        if (sieve == 0) croak("Could not generate sieve for %"UVuf, high);
         START_DO_FOR_EACH_SIEVE_PRIME( sieve, low, high ) {
            av_push(av,newSVuv(p));
         } END_DO_FOR_EACH_SIEVE_PRIME
         Safefree(sieve);
+      } else if (ix == 3) {                   /* Segment */
+        unsigned char* segment;
+        UV seg_base, seg_low, seg_high;
+        void* ctx = start_segment_primes(low, high, &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 )
+            av_push(av,newSVuv( seg_base + p ));
+          END_DO_FOR_EACH_SIEVE_PRIME
+        }
+        end_segment_primes(ctx);
       }
     }
     RETVAL = newRV_noinc( (SV*) av );
   OUTPUT:
     RETVAL
 
-
-#define SIMPLE_FACTOR(func, n, arg1) \
-    if (n <= 1) { \
-      if (n == 0) \
-        XPUSHs(sv_2mortal(newSVuv( n ))); \
-    } else { \
-      while ( (n% 2) == 0 ) {  n /=  2;  XPUSHs(sv_2mortal(newSVuv( 2 ))); } \
-      while ( (n% 3) == 0 ) {  n /=  3;  XPUSHs(sv_2mortal(newSVuv( 3 ))); } \
-      while ( (n% 5) == 0 ) {  n /=  5;  XPUSHs(sv_2mortal(newSVuv( 5 ))); } \
-      if (n == 1) {  /* done */ } \
-      else if (_XS_is_prime(n)) { XPUSHs(sv_2mortal(newSVuv( n ))); } \
-      else { \
-        UV factors[MPU_MAX_FACTORS+1]; \
-        int i, nfactors; \
-        nfactors = func(n, factors, arg1); \
-        for (i = 0; i < nfactors; i++) { \
-          XPUSHs(sv_2mortal(newSVuv( factors[i] ))); \
-        } \
-      } \
-    }
-#define SIMPLE_FACTOR_2ARG(func, n, arg1, arg2) \
-    /* Stupid MSVC won't bring its C compiler out of the 1980s. */ \
-    if (n <= 1) { \
-      if (n == 0) \
-        XPUSHs(sv_2mortal(newSVuv( n ))); \
-    } else { \
-      while ( (n% 2) == 0 ) {  n /=  2;  XPUSHs(sv_2mortal(newSVuv( 2 ))); } \
-      while ( (n% 3) == 0 ) {  n /=  3;  XPUSHs(sv_2mortal(newSVuv( 3 ))); } \
-      while ( (n% 5) == 0 ) {  n /=  5;  XPUSHs(sv_2mortal(newSVuv( 5 ))); } \
-      if (n == 1) {  /* done */ } \
-      else if (_XS_is_prime(n)) { XPUSHs(sv_2mortal(newSVuv( n ))); } \
-      else { \
-        UV factors[MPU_MAX_FACTORS+1]; \
-        int i, nfactors; \
-        nfactors = func(n, factors, arg1, arg2); \
-        for (i = 0; i < nfactors; i++) { \
-          XPUSHs(sv_2mortal(newSVuv( factors[i] ))); \
-        } \
-      } \
-    }
-
-void
-_XS_factor(IN UV n)
-  PREINIT:
-    UV factors[MPU_MAX_FACTORS+1];
-    int i, nfactors;
-  PPCODE:
-    nfactors = factor(n, factors);
-    if (GIMME_V == G_SCALAR) {
-      PUSHs(sv_2mortal(newSVuv(nfactors)));
-    } else if (GIMME_V == G_ARRAY) {
-      EXTEND(SP, nfactors);
-      for (i = 0; i < nfactors; i++) {
-        PUSHs(sv_2mortal(newSVuv( factors[i] )));
-      }
-    }
-
 void
 _XS_factor_exp(IN UV n)
   PREINIT:
@@ -437,51 +323,54 @@ _XS_divisors(IN UV n)
     }
 
 void
-trial_factor(IN UV n, IN UV maxfactor = 0)
-  PPCODE:
-    SIMPLE_FACTOR(trial_factor, n, maxfactor);
-
-void
-fermat_factor(IN UV n, IN UV maxrounds = 64*1024*1024)
-  PPCODE:
-    SIMPLE_FACTOR(fermat_factor, n, maxrounds);
-
-void
-holf_factor(IN UV n, IN UV maxrounds = 8*1024*1024)
-  PPCODE:
-    SIMPLE_FACTOR(holf_factor, n, maxrounds);
-
-void
-squfof_factor(IN UV n, IN UV maxrounds = 4*1024*1024)
-  PPCODE:
-    SIMPLE_FACTOR(squfof_factor, n, maxrounds);
-
-void
-rsqufof_factor(IN UV n, IN UV maxrounds = 4*1024*1024)
-  PPCODE:
-    SIMPLE_FACTOR(racing_squfof_factor, n, maxrounds);
-
-void
-pbrent_factor(IN UV n, IN UV maxrounds = 4*1024*1024)
-  PPCODE:
-    SIMPLE_FACTOR(pbrent_factor_a1, n, maxrounds);
-
-void
-prho_factor(IN UV n, IN UV maxrounds = 4*1024*1024)
-  PPCODE:
-    SIMPLE_FACTOR(prho_factor, n, maxrounds);
-
-void
-pminus1_factor(IN UV n, IN UV B1 = 1*1024*1024, IN UV B2 = 0)
-  PPCODE:
-    if (B2 == 0)
-      B2 = 10*B1;
-    SIMPLE_FACTOR_2ARG(pminus1_factor, n, B1, B2);
-
-void
-pplus1_factor(IN UV n, IN UV B = 200)
+trial_factor(IN UV n, ...)
+  ALIAS:
+    fermat_factor = 1
+    holf_factor = 2
+    squfof_factor = 3
+    rsqufof_factor = 4
+    pbrent_factor = 5
+    prho_factor = 6
+    pplus1_factor = 7
+    pminus1_factor = 8
   PPCODE:
-    SIMPLE_FACTOR(pplus1_factor, n, B);
+    if (n == 0)  XSRETURN_UV(0);
+    while ( (n% 2) == 0 ) {  n /=  2;  XPUSHs(sv_2mortal(newSVuv( 2 ))); }
+    while ( (n% 3) == 0 ) {  n /=  3;  XPUSHs(sv_2mortal(newSVuv( 3 ))); }
+    while ( (n% 5) == 0 ) {  n /=  5;  XPUSHs(sv_2mortal(newSVuv( 5 ))); }
+    if (n == 1) {  /* done */ }
+    else if (_XS_is_prime(n)) { XPUSHs(sv_2mortal(newSVuv( n ))); }
+    else {
+      UV arg1, arg2, factors[MPU_MAX_FACTORS+1];
+      int i, nfactors = 0;
+      switch (ix) {
+        case 0:  arg1 = (items < 2)  ?  0             : SvUV(ST(1));
+                 nfactors = trial_factor  (n, factors, arg1);  break;
+        case 1:  arg1 = (items < 2)  ?  64*1024*1024  : SvUV(ST(1));
+                 nfactors = fermat_factor (n, factors, arg1);  break;
+        case 2:  arg1 = (items < 2)  ?   8*1024*1024  : SvUV(ST(1));
+                 nfactors = holf_factor   (n, factors, arg1);  break;
+        case 3:  arg1 = (items < 2)  ?   4*1024*1024  : SvUV(ST(1));
+                 nfactors = squfof_factor (n, factors, arg1);  break;
+        case 4:  arg1 = (items < 2)  ?   4*1024*1024  : SvUV(ST(1));
+                 nfactors = racing_squfof_factor(n, factors, arg1);  break;
+        case 5:  arg1 = (items < 2)  ?   4*1024*1024  : SvUV(ST(1));
+                 arg2 = (items < 3)  ?             1  : SvUV(ST(2));
+                 nfactors = pbrent_factor (n, factors, arg1, arg2);  break;
+        case 6:  arg1 = (items < 2)  ?   4*1024*1024  : SvUV(ST(1));
+                 nfactors = prho_factor   (n, factors, arg1);  break;
+        case 7:  arg1 = (items < 2)  ?           200  : SvUV(ST(1));
+                 nfactors = pplus1_factor (n, factors, arg1);  break;
+        case 8:  arg1 = (items < 2)  ?   1*1024*1024  : SvUV(ST(1));
+                 arg2 = (items < 3)  ?             0  : SvUV(ST(2));
+                 if (arg2 == 0) arg2 = 10*arg1;  /* default B2 */
+                 nfactors = pminus1_factor(n, factors, arg1, arg2);  break;
+        default: break;
+      }
+      EXTEND(SP, nfactors);
+      for (i = 0; i < nfactors; i++)
+        PUSHs(sv_2mortal(newSVuv( factors[i] )));
+    }
 
 int
 _XS_is_pseudoprime(IN UV n, IN UV a)
@@ -558,7 +447,7 @@ _XS_is_almost_extra_strong_lucas_pseudoprime(IN UV n, IN UV 
increment = 1)
   OUTPUT:
     RETVAL
 
-int
+void
 is_prime(IN SV* svn)
   ALIAS:
     is_prob_prime = 1
@@ -608,6 +497,47 @@ next_prime(IN SV* n)
     XSRETURN(1);
 
 void
+factor(IN SV* svn)
+  PREINIT:
+    int status, i, nfactors;
+  PPCODE:
+    status = _validate_int(svn, 0);
+    if (status == 1) {
+      UV n, factors[MPU_MAX_FACTORS+1];
+      set_val_from_sv(n, svn);
+      nfactors = factor(n, factors);
+      if (GIMME_V == G_SCALAR) {
+        PUSHs(sv_2mortal(newSVuv(nfactors)));
+      } else if (GIMME_V == G_ARRAY) {
+        EXTEND(SP, nfactors);
+        for (i = 0; i < nfactors; i++) {
+          PUSHs(sv_2mortal(newSVuv( factors[i] )));
+        }
+      }
+    } else {
+      XSRETURN(_vcallsubn(GIMME_V, "Math::Prime::Util::_generic_factor", 1));
+    }
+
+
+void
+znorder(IN SV* sva, IN SV* svn)
+  PREINIT:
+    int astatus, nstatus;
+  PPCODE:
+    astatus = _validate_int(sva, 0);
+    nstatus = _validate_int(svn, 0);
+    if (astatus == 1 && nstatus == 1) {
+      UV a, n, order;
+      set_val_from_sv(a, sva);
+      set_val_from_sv(n, svn);
+      order = znorder(a, n);
+      if (order == 0) XSRETURN_UNDEF;
+      XSRETURN_UV(order);
+    } else {
+      XSRETURN( _vcallsubn(G_SCALAR, "Math::Prime::Util::_generic_znorder", 2) 
);
+    }
+
+void
 znprimroot(IN SV* svn)
   PREINIT:
     int status;
@@ -625,224 +555,158 @@ znprimroot(IN SV* svn)
     _vcallsub("Math::Prime::Util::_generic_znprimroot");
     XSRETURN(1);
 
-int
+void
 kronecker(IN SV* sva, IN SV* svb)
   PREINIT:
     int astatus, bstatus;
-  CODE:
+  PPCODE:
     astatus = _validate_int(sva, 2);
     bstatus = _validate_int(svb, 2);
     if (astatus == 1 && bstatus == 1) {
       UV a, b;
       set_val_from_sv(a, sva);
       set_val_from_sv(b, svb);
-      RETVAL = kronecker_uu(a, b);
+      XSRETURN_IV( kronecker_uu(a, b) );
     } else if (astatus != 0 && SvIOK(sva) && !SvIsUV(sva) &&
                bstatus != 0 && SvIOK(svb) && !SvIsUV(svb) ) {
       IV a, b;
       set_sval_from_sv(a, sva);
       set_sval_from_sv(b, svb);
-      RETVAL = kronecker_ss(a, b);
+      XSRETURN_IV( kronecker_ss(a, b) );
     } else {
-      dTHX;
-      dSP;
-      int count;
-      ENTER;
-      SAVETMPS;
-      PUSHMARK(SP);
-      XPUSHs(sva);
-      XPUSHs(svb);
-      PUTBACK;
-      count = call_pv("Math::Prime::Util::_generic_kronecker", G_SCALAR);
-      SPAGAIN;
-      if (count != 1) croak("callback sub should return one value");
-      RETVAL = POPi;
-      PUTBACK;
-      FREETMPS;
-      LEAVE;
+      XSRETURN( _vcallsubn(G_SCALAR, "Math::Prime::Util::_generic_kronecker", 
2) );
     }
-  OUTPUT:
-    RETVAL
 
 double
-_XS_ExponentialIntegral(IN double x)
+_XS_ExponentialIntegral(IN SV* x)
   ALIAS:
     _XS_LogarithmicIntegral = 1
     _XS_RiemannZeta = 2
     _XS_RiemannR = 3
+    _XS_chebyshev_theta = 4
+    _XS_chebyshev_psi = 5
   PREINIT:
     double ret;
   CODE:
     switch (ix) {
-      case 0: ret = _XS_ExponentialIntegral(x); break;
-      case 1: ret = _XS_LogarithmicIntegral(x); break;
-      case 2: ret = (double) ld_riemann_zeta(x); break;
-      case 3: ret = _XS_RiemannR(x); break;
-      default: croak("_XS_ExponentialIntegral: Unknown function alias"); break;
-    }
-    RETVAL = ret;
-  OUTPUT:
-    RETVAL
-
-double
-_XS_chebyshev_theta(IN UV n)
-  ALIAS:
-    _XS_chebyshev_psi = 1
-  PREINIT:
-    double ret;
-  CODE:
-    switch (ix) {
-      case 0: ret = _XS_chebyshev_theta(n); break;
-      case 1: ret = _XS_chebyshev_psi(n); break;
-      default: croak("_XS_chebyshev_theta: Unknown function alias"); break;
+      case 0: ret = _XS_ExponentialIntegral(SvNV(x)); break;
+      case 1: ret = _XS_LogarithmicIntegral(SvNV(x)); break;
+      case 2: ret = (double) ld_riemann_zeta(SvNV(x)); break;
+      case 3: ret = _XS_RiemannR(SvNV(x)); break;
+      case 4: ret = _XS_chebyshev_theta(SvUV(x)); break;
+      case 5: ret = _XS_chebyshev_psi(SvUV(x)); break;
+      default: break;
     }
     RETVAL = ret;
   OUTPUT:
     RETVAL
 
 void
-_XS_totient(IN UV lo, IN UV hi = 0)
+euler_phi(IN SV* svlo, ...)
   PREINIT:
-    UV i;
+    int lostatus, histatus;
+    UV i, lo, hi;
   PPCODE:
-    if (hi != lo && hi != 0) { /* Totients in a range, returns array */
-      UV* totients;
-      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;
+    if (items == 1) {
+      int lostatus = _validate_int(svlo, 1);
+      if (lostatus == -1) {      /*  I like SAGE's decision that    */
+        XSRETURN_UV(0);          /*  totient(n) = 0 if n <= 0       */
+      } else if (lostatus == 1) {
+        UV lo;
+        set_val_from_sv(lo, svlo);
+        XSRETURN_UV(totient(lo));
+      } else {
+        XSRETURN( _vcallsubn(G_SCALAR, 
"Math::Prime::Util::_generic_euler_phi", 1) );
       }
-      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);
+    } else if (items == 2) {
+      SV* svhi = ST(1);
+      int lostatus = _validate_int(svlo, 1);
+      int histatus = _validate_int(svhi, 1);
+      if (lostatus == 1 && histatus == 1) {
+        UV lo, hi;
+        set_val_from_sv(lo, svlo);
+        set_val_from_sv(hi, svhi);
+        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;
+        }
+        if (hi >= lo) {
+          UV* 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);
+        }
+      } else {
+        XSRETURN( _vcallsubn(G_ARRAY, "Math::Prime::Util::_generic_euler_phi", 
2) );
       }
     } else {
-      XSRETURN_UV(totient(lo));
-    }
-
-void
-carmichael_lambda(IN SV* svn)
-  PREINIT:
-    int status;
-  PPCODE:
-    status = _validate_int(svn, 0);
-    if (status == 1) {
-      UV n;
-      set_val_from_sv(n, svn);
-      XSRETURN_UV(carmichael_lambda(n));
-    }
-    _vcallsub("Math::Prime::Util::_generic_carmichael_lambda");
-    XSRETURN(1);
-
-int
-znorder(IN SV* sva, IN SV* svn)
-  PREINIT:
-    int astatus, nstatus;
-  PPCODE:
-    astatus = _validate_int(sva, 0);
-    nstatus = _validate_int(svn, 0);
-    if (astatus == 1 && nstatus == 1) {
-      UV a, n, order;
-      set_val_from_sv(a, sva);
-      set_val_from_sv(n, svn);
-      order = znorder(a, n);
-      if (order == 0) XSRETURN_UNDEF;
-      XSRETURN_UV(order);
-    } else {
-      dTHX;
-      dSP;
-      int count;
-      ENTER;
-      SAVETMPS;
-      (void) POPs;  (void) POPs;
-      PUSHMARK(SP);
-      XPUSHs(sva);
-      XPUSHs(svn);
-      PUTBACK;
-      count = call_pv("Math::Prime::Util::_generic_znorder", G_SCALAR);
-      SPAGAIN;
-      if (count != 1) croak("callback sub should return one value");
-      TOPs = SvREFCNT_inc(TOPs);
-      PUTBACK;
-      FREETMPS;
-      LEAVE;
-      TOPs = sv_2mortal(TOPs);
-      XSRETURN(1);
+      croak("Usage: euler_phi(n) or euler_phi(1o,hi)");
     }
-
+ 
 void
-_XS_moebius(IN UV lo, IN UV hi = 0)
-  PREINIT:
-    UV i;
+moebius(IN SV* svlo, ...)
   PPCODE:
-    if (hi != lo && hi != 0) {   /* mobius in a range */
-      signed char* mu = _moebius_range(lo, hi);
-      MPUassert( mu != 0, "_moebius_range returned 0" );
-      EXTEND(SP, hi-lo+1);
-      for (i = lo; i <= hi; i++)
-        PUSHs(sv_2mortal(newSViv(mu[i-lo])));
-      Safefree(mu);
+    if (items == 1) {
+      int nstatus = _validate_int(svlo, 0);
+      if (nstatus == 1) {
+        UV n;
+        set_val_from_sv(n, svlo);
+        XSRETURN_IV(moebius(n));
+      } else {
+        XSRETURN(_vcallsubn(G_SCALAR, 
"Math::Prime::Util::_generic_moebius",1));
+      }
+    } else if (items == 2) {
+      SV* svhi = ST(1);
+      int lostatus = _validate_int(svlo, 0);
+      int histatus = _validate_int(svhi, 0);
+      if (lostatus == 1 && histatus == 1) {
+        UV i, lo, hi;
+        set_val_from_sv(lo, svlo);
+        set_val_from_sv(hi, svhi);
+        if (hi < lo) XSRETURN_EMPTY;
+        if (hi >= lo) {
+          signed char* mu = _moebius_range(lo, hi);
+          MPUassert( mu != 0, "_moebius_range returned 0" );
+          EXTEND(SP, hi-lo+1);
+          for (i = lo; i <= hi; i++)
+            PUSHs(sv_2mortal(newSViv(mu[i-lo])));
+          Safefree(mu);
+        }
+      } else {
+        XSRETURN(_vcallsubn(G_ARRAY, "Math::Prime::Util::_generic_moebius",2));
+      }
     } else {
-      UV factors[MPU_MAX_FACTORS+1];
-      UV nfactors;
-      UV n = lo;
-
-      if (n <= 1)
-        XSRETURN_IV(n);
-
-      if ( (!(n% 4) && n >=  4) || (!(n% 9) && n >=  9) ||
-           (!(n%25) && n >= 25) || (!(n%49) && n >= 49) )
-        XSRETURN_IV(0);
-
-      nfactors = factor(n, factors);
-      for (i = 1; i < nfactors; i++)
-        if (factors[i] == factors[i-1])
-          XSRETURN_IV(0);
-
-      XSRETURN_IV( (nfactors % 2) ? -1 : 1 );
+      croak("Usage: moebius(n) or moebius(1o,hi)");
     }
 
 IV
 _XS_mertens(IN UV n)
 
+
 void
-exp_mangoldt(IN SV* svn)
+carmichael_lambda(IN SV* svn)
+  ALIAS:
+    exp_mangoldt = 1
   PREINIT:
     int status;
     UV n;
   PPCODE:
-    status = _validate_int(svn, 1);
+    status = _validate_int(svn, (ix == 0) ? 0 : 1);
     if (status == -1) {
       XSRETURN_UV(1);
     } else if (status == 1) {
+      UV n;
       set_val_from_sv(n, svn);
-      if (n <= 1)
-        XSRETURN_UV(1);
-      else if ((n & (n-1)) == 0)  /* Power of 2 */
-        XSRETURN_UV(2);
-      else if ((n & 1) == 0)      /* Even number */
-        XSRETURN_UV(1);
-      else {
-        UV factors[MPU_MAX_FACTORS+1];
-        UV nfactors, i;
-        /* We could try a partial factor, e.g. looking for two small factors */
-        /* We could also check powers of primes searching for n */
-        nfactors = factor(n, factors);
-        for (i = 1; i < nfactors; i++) {
-          if (factors[i] != factors[0])
-            XSRETURN_UV(1);
-        }
-        XSRETURN_UV(factors[0]);
-      }
-    } else {
-      _vcallsub("Math::Prime::Util::_generic_exp_mangoldt");
-      XSRETURN(1);
+      if (ix == 0) XSRETURN_UV(carmichael_lambda(n));
+      else         XSRETURN_UV(exp_mangoldt(n));
     }
+    _vcallsub( (ix == 0) ? "Math::Prime::Util::_generic_carmichael_lambda"
+                         : "Math::Prime::Util::_generic_exp_mangoldt" );
+    XSRETURN(1);
 
 int
 _validate_num(SV* n, ...)
diff --git a/lib/Math/Prime/Util.pm b/lib/Math/Prime/Util.pm
index fa11fa9..0fc5705 100644
--- a/lib/Math/Prime/Util.pm
+++ b/lib/Math/Prime/Util.pm
@@ -60,7 +60,6 @@ sub import {
 sub _import_nobigint {
   $_Config{'nobigint'} = 1;
   return unless $_Config{'xs'};
-  undef *factor;          *factor            = \&_XS_factor;
   undef *factor_exp;      *factor_exp        = \&_XS_factor_exp;
   undef *divisors;        *divisors          = \&_XS_divisors;
  #undef *prime_count;     *prime_count       = \&_XS_prime_count;
@@ -69,7 +68,6 @@ sub _import_nobigint {
   undef *is_strong_pseudoprime;  *is_strong_pseudoprime = \&_XS_miller_rabin;
   undef *moebius;         *moebius           = \&_XS_moebius;
   undef *mertens;         *mertens           = \&_XS_mertens;
-  undef *euler_phi;       *euler_phi         = \&_XS_totient;
   undef *chebyshev_theta; *chebyshev_theta   = \&_XS_chebyshev_theta;
   undef *chebyshev_psi;   *chebyshev_psi     = \&_XS_chebyshev_psi;
   # These should be fast anyway, but this skips validation.
@@ -105,10 +103,13 @@ BEGIN {
     *next_prime    = \&Math::Prime::Util::_generic_next_prime;
     *prev_prime    = \&Math::Prime::Util::_generic_prev_prime;
     *exp_mangoldt  = \&Math::Prime::Util::_generic_exp_mangoldt;
+    *euler_phi     = \&Math::Prime::Util::_generic_euler_phi;
+    *moebius       = \&Math::Prime::Util::_generic_moebius;
     *carmichael_lambda = \&Math::Prime::Util::_generic_carmichael_lambda;
     *kronecker     = \&Math::Prime::Util::_generic_kronecker;
     *znorder       = \&Math::Prime::Util::_generic_znorder;
     *znprimroot    = \&Math::Prime::Util::_generic_znprimroot;
+    *factor        = \&Math::Prime::Util::_generic_factor;
     *forprimes     = sub (&$;$) { _generic_forprimes(@_); }; ## no critic 
qw(ProhibitSubroutinePrototypes)
     *fordivisors   = sub (&$) { _generic_fordivisors(@_); }; ## no critic 
qw(ProhibitSubroutinePrototypes)
     *forcomposites = sub (&$) { _generic_forcomposites(@_); }; ## no critic 
qw(ProhibitSubroutinePrototypes)
@@ -219,7 +220,11 @@ sub prime_set_config {
 
 sub _validate_positive_integer {
   my($n, $min, $max) = @_;
-  # We've gone through _validate_num already, so we just need to handle bigints
+  # We need to handle bigints, magic variables, and coderefs
+  if (ref($n) eq 'CODE') {
+    $_[0] = $_[0]->();
+    $n = $_[0];
+  }
   croak "Parameter '$n' must be a positive integer"
      if ref($n) eq 'Math::BigInt' && $n->sign() ne '+';
   croak "Parameter '$n' must be >= $min" if defined $min && $n < $min;
@@ -1257,58 +1262,15 @@ sub divisors {
 # alias the old "all_factors" to the new name: divisors
 *all_factors = \&divisors;
 
-
 # A008683 Moebius function mu(n)
 # A030059, A013929, A030229, A002321, A005117, A013929 all relate.
-sub moebius {
+sub _generic_moebius {
   my($n, $nend) = @_;
+  return 0 if defined $n && $n < 0;
   _validate_num($n) || _validate_positive_integer($n);
-
-  if (defined $nend) {
-    _validate_num($nend) || _validate_positive_integer($nend);
-    return if $nend < $n;
-  } else {
-    $nend = $n;
-  }
-  return _XS_moebius($n, $nend) if $nend <= $_XS_MAXVAL;
-
-  # Moebius over a range.
-  if ($nend != $n) {
-    my ($lo,$hi) = ($n,$nend);
-    my @mu = map { 1 } $lo .. $hi;
-    $mu[0] = 0 if $lo == 0;
-    my $sqrtn = int(sqrt($hi)+0.5);
-    forprimes {
-      my $p = $_;
-      my $i = $p * $p;
-      $i = $i * int($lo/$i) + (($lo % $i)  ? $i : 0)  if $i < $lo;
-      while ($i <= $hi) {
-        $mu[$i-$lo] = 0;
-        $i += $p * $p;
-      }
-      $i = $p;
-      $i = $i * int($lo/$i) + (($lo % $i)  ? $i : 0)  if $i < $lo;
-      while ($i <= $hi) {
-        $mu[$i-$lo] *= -$p;
-        $i += $p;
-      }
-    } $sqrtn;
-    foreach my $i ($lo .. $hi) {
-      my $m = $mu[$i-$lo];
-      $m *= -1 if abs($m) != $i;
-      $mu[$i-$lo] = ($m>0) - ($m<0);
-    }
-    return @mu;
-  }
-
-  return $n if $n <= 1;
-  # Quick check for small replicated factors
-  return 0 if ($n >= 25) && (!($n % 4) || !($n % 9) || !($n % 25));
-  my @factors = factor($n);
-  foreach my $i (1 .. $#factors) {
-    return 0 if $factors[$i] == $factors[$i-1];
-  }
-  return (((scalar @factors) % 2) == 0) ? 1 : -1;
+  return Math::Prime::Util::PP::moebius($n) if !defined $nend;
+  _validate_num($nend) || _validate_positive_integer($nend);
+  return Math::Prime::Util::PP::moebius_range($n, $nend);
 }
 
 # A002321 Mertens' function.  mertens(n) = sum(moebius(1,n))
@@ -1346,56 +1308,13 @@ sub mertens {
 
 
 # A000010 Euler Phi, aka Euler Totient
-sub euler_phi {
+sub _generic_euler_phi {
   my($n, $nend) = @_;
-  # SAGE defines this to be 0 for all n <= 0.  Others choose differently.
-  # I am following SAGE's decision for n <= 0.
   return 0 if defined $n && $n < 0;
   _validate_num($n) || _validate_positive_integer($n);
-  if (defined $nend) {
-    _validate_num($nend) || _validate_positive_integer($nend);
-    return if $nend < $n;
-  } else {
-    $nend = $n;
-  }
-  return _XS_totient($n, $nend) if $nend <= $_XS_MAXVAL;
-
-  # Totient over a range.  Could be improved, as this can use huge memory.
-  if ($nend != $n) {
-    return () if $nend < $n;
-    my @totients = (0 .. $nend);
-    foreach my $i (2 .. $nend) {
-      next unless $totients[$i] == $i;
-      $totients[$i] = $i-1;
-      foreach my $j (2 .. int($nend / $i)) {
-        $totients[$i*$j] -= $totients[$i*$j]/$i;
-      }
-    }
-    splice(@totients, 0, $n) if $n > 0;
-    return @totients;
-  }
-
-  return $n if $n <= 1;
-
-  my @pe = factor_exp($n);
-  my $totient = $n - $n + 1;
-
-  if (ref($n) ne 'Math::BigInt') {
-    foreach my $f (@pe) {
-      my ($p, $e) = @$f;
-      $totient *= $p - 1;
-      $totient *= $p for 2 .. $e;
-    }
-  } else {
-    my $zero = $n->copy->bzero;
-    foreach my $f (@pe) {
-      my ($p, $e) = @$f;
-      $p = $zero->copy->badd("$p");
-      $totient->bmul($p->copy->bdec());
-      $totient->bmul($p) for 2 .. $e;
-    }
-  }
-  return $totient;
+  return Math::Prime::Util::PP::euler_phi($n) if !defined $nend;
+  _validate_num($nend) || _validate_positive_integer($nend);
+  return Math::Prime::Util::PP::euler_phi_range($n, $nend);
 }
 
 # Jordan's totient -- a generalization of Euler's totient.
@@ -1600,8 +1519,7 @@ sub _generic_exp_mangoldt {
 sub liouville {
   my($n) = @_;
   _validate_num($n) || _validate_positive_integer($n);
-  my $l = ($n <= $_XS_MAXVAL)  ?  (-1) ** scalar _XS_factor($n)
-                               :  (-1) ** scalar factor($n);
+  my $l = (-1) ** scalar factor($n);
   return $l;
 }
 
@@ -1891,7 +1809,7 @@ sub nth_prime {
   return Math::Prime::Util::PP::nth_prime($n);
 }
 
-sub factor {
+sub _generic_factor {
   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 1f0b817..d5383bb 100644
--- a/lib/Math/Prime/Util/PP.pm
+++ b/lib/Math/Prime/Util/PP.pm
@@ -447,6 +447,104 @@ sub prev_prime {
   #$d*30+$m;
 }
 
+sub euler_phi {
+  my($n) = @_;
+  return 0 if $n < 0;
+  return $n if $n <= 1;
+
+  my @pe = Math::Prime::Util::factor_exp($n);
+  my $totient = $n - $n + 1;
+
+  if (ref($n) ne 'Math::BigInt') {
+    foreach my $f (@pe) {
+      my ($p, $e) = @$f;
+      $totient *= $p - 1;
+      $totient *= $p for 2 .. $e;
+    }
+  } else {
+    my $zero = $n->copy->bzero;
+    foreach my $f (@pe) {
+      my ($p, $e) = @$f;
+      $p = $zero->copy->badd("$p");
+      $totient->bmul($p->copy->bdec());
+      $totient->bmul($p) for 2 .. $e;
+    }
+  }
+  return $totient;
+}
+
+sub euler_phi_range {
+  my($n, $nend) = @_;
+  return () if $nend < $n;
+  return euler_phi($n) if $n == $nend;
+  my @totients;
+  if ($nend > 2**30) {
+    while ($n < $nend) {
+      push @totients, euler_phi($n++);
+    }
+  } else {
+    @totients = (0 .. $nend);
+    foreach my $i (2 .. $nend) {
+      next unless $totients[$i] == $i;
+      $totients[$i] = $i-1;
+      foreach my $j (2 .. int($nend / $i)) {
+        $totients[$i*$j] -= $totients[$i*$j]/$i;
+      }
+    }
+    splice(@totients, 0, $n) if $n > 0;
+  }
+  return @totients;
+}
+
+sub moebius {
+  my($n) = @_;
+  return 0 if $n <= 0;
+  return 1 if $n == 1;
+  return 0 if ($n >= 25) && (!($n % 4) || !($n % 9) || !($n % 25));
+  my @factors = Math::Prime::Util::factor($n);
+  foreach my $i (1 .. $#factors) {
+    return 0 if $factors[$i] == $factors[$i-1];
+  }
+  return (((scalar @factors) % 2) == 0) ? 1 : -1;
+}
+
+sub moebius_range {
+  my($lo, $hi) = @_;
+  return () if $hi < $lo;
+  return moebius($lo) if $lo == $hi;
+  if ($hi > 2**32) {
+    my @mu;
+    while ($lo < $hi) {
+      push @mu, moebius($lo++);
+    }
+    return @mu;
+  }
+  my @mu = map { 1 } $lo .. $hi;
+  $mu[0] = 0 if $lo == 0;
+  my($p, $sqrtn) = (2, int(sqrt($hi)+0.5));
+  while ($p <= $sqrtn) {
+    my $i = $p * $p;
+    $i = $i * int($lo/$i) + (($lo % $i)  ? $i : 0)  if $i < $lo;
+    while ($i <= $hi) {
+      $mu[$i-$lo] = 0;
+      $i += $p * $p;
+    }
+    $i = $p;
+    $i = $i * int($lo/$i) + (($lo % $i)  ? $i : 0)  if $i < $lo;
+    while ($i <= $hi) {
+      $mu[$i-$lo] *= -$p;
+      $i += $p;
+    }
+    $p = next_prime($p);
+  }
+  foreach my $i ($lo .. $hi) {
+    my $m = $mu[$i-$lo];
+    $m *= -1 if abs($m) != $i;
+    $mu[$i-$lo] = ($m>0) - ($m<0);
+  }
+  return @mu;
+}
+
 #############################################################################
 #                       Lehmer prime count
 #

-- 
Alioth's /usr/local/bin/git-commit-notice on 
/srv/git.debian.org/git/pkg-perl/packages/libmath-prime-util-perl.git

_______________________________________________
Pkg-perl-cvs-commits mailing list
Pkg-perl-cvs-commits@lists.alioth.debian.org
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-perl-cvs-commits

Reply via email to