[libmath-prime-util-perl] 105/181: More XS->Perl changes. Add constant SV* returns for -1, 0, 1, 2.

Partha P. Mukherjee ppm-guest at moszumanska.debian.org
Thu May 21 18:51:11 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 e12acebe9ba1125b87e9be02300901121415fae6
Author: Dana Jacobsen <dana at acm.org>
Date:   Thu Jan 2 19:37:21 2014 -0800

    More XS->Perl changes.  Add constant SV* returns for -1,0,1,2.
---
 Changes                   |  31 ++++---
 XS.xs                     | 164 +++++++++++++++++++----------------
 lib/Math/Prime/Util.pm    | 216 ++++++++--------------------------------------
 lib/Math/Prime/Util/PP.pm |  36 +++++---
 t/80-pp.t                 |  16 ++--
 util.c                    |   2 +-
 6 files changed, 177 insertions(+), 288 deletions(-)

diff --git a/Changes b/Changes
index 51dda6a..582abf3 100644
--- a/Changes
+++ b/Changes
@@ -4,9 +4,9 @@ Revision history for Perl module Math::Prime::Util
 
     [API Changes]
 
-    - factor behavior for 0 and 1 more consistent.  The results for factor,
-      factor_exp, divisors, and divisor_sum should now match Pari, and the
-      omega/Omega exception for 1 is removed.
+    - factor behavior for 0 and 1 more consistent.  The results for
+      factor, factor_exp, divisors, and divisor_sum now match Pari,
+      and the omega(1)/Omega(1) exception is removed.
 
       Thanks to Hugo van der Sanden for bringing this up.
 
@@ -23,12 +23,22 @@ Revision history for Perl module Math::Prime::Util
 
     - Win32 fixes from bulk88 / bulkdd.  Thanks!
 
-    - Lots of XS interface reorgs.
+    - XS redundancy removal and fixes from bulk88 and leont.  Smaller DLL.
+      This almost includes not compiling a number of prime count methods
+      (Legendre, Meissel, Lehmer, and LMOS) that are not used.  Using
+      "-DLEHMER" in the Makefile will compile them, but there should not
+      be any reason to do so.
 
-    - XS reduncies and fixes from bulk88 and leont.
+    - Big XS interface reorg.  Most functions now go straight to XS, which
+      reduces their overhead.  Input number validation is much faster for
+      the general case.  Those two combined meant the '-nobigint' import
+      no longer serves any good purpose.
 
-    - Speedup for input number validation: speedup for all functions,
-      especially noticeable with fast functions (e.g. small n is_prime(n)).
+    - More functions will go from XS directly to the GMP module, bypassing
+      the Perl layer entirely.  The upside is less overhead, both for the
+      case of having GMP, and without.  In the contrived case of having XS
+      turned off but the GMP module enabled, things will run slower since
+      they no longer go to GMP.
 
     - Some 5.6.2-is-broken workarounds.
 
@@ -41,17 +51,14 @@ Revision history for Perl module Math::Prime::Util
     - divisors (all_factors) faster for native size numbers with many factors.
 
     - Switch from mapes to a cached primorial/totient small phi method in
-      lehmer.c.  Really only affects LMOS and Legendre, but it's significant
-      for them.  Thanks to Kim Walisch for questioning my earlier decision.
+      lehmer.c.  Significant for LMOS and Legendre (no longer used or compiled,
+      see earlier.  Thanks to Kim Walisch for questioning my earlier decision.
 
     - Rewrite sieve composite map.  Segment sieving is faster.  It's a little
       faster than primegen for me, but still slower than primesieve and yafu.
 
     - znorder uses Carmichael Lambda instead of Euler Phi.  Faster.
 
-    - Legendre, Meissel, Lehmer, and LMOS methods are no longer compiled by
-      default.  Add -DLEHMER if you really want access to them.
-
 
 0.35  2013-12-08
 
diff --git a/XS.xs b/XS.xs
index ff3dbe0..396b0a3 100644
--- a/XS.xs
+++ b/XS.xs
@@ -153,17 +153,33 @@ static int _validate_int(pTHX_ SV* n, int negok)
 }
 
 /* Call a Perl sub to handle work for us. */
-static int _vcallsubn(pTHX_ I32 flags, const char* name, int nargs)
+static int _vcallsubn(pTHX_ I32 flags, const char* gmp_name, const char* name, int nargs)
 {
     dSP;
     char fullname[80] = "Math::Prime::Util::";
-    strncat(fullname, name, 60);
+    /* If given a GMP function, and GMP enabled, and function exists, use it. */
+    int use_gmp = gmp_name != 0 && _XS_get_callgmp();
+    if (use_gmp) {
+      strncat(fullname, gmp_name, 60);
+      if (get_cv(fullname, flags) == 0)
+        use_gmp = 0;
+    }
+    if (!use_gmp)
+      strncat(fullname, name, 60);
     PUSHMARK(SP-nargs);
     PUTBACK;
     return call_pv(fullname, flags);
 }
-#define _vcallsub(func) (void)_vcallsubn(aTHX_ G_SCALAR, func, 1)
+#define _vcallsub(func) (void)_vcallsubn(aTHX_ G_SCALAR, 0, func, items)
+#define _vcallsub_with_gmp(func) (void)_vcallsubn(aTHX_ G_SCALAR, "GMP::" func, "PP::" func, items)
 
+static SV* const_int[4] = {0};   /* -1, 0, 1, 2 */
+/* I wish I had a better name for this */
+#define RETURN_NPARITY(ret) \
+  do { int r_ = ret; \
+       if (r_ >= -1 && r_ <= 2) { ST(0) = const_int[r_+1]; XSRETURN(1); } \
+       else                     { XSRETURN_IV(r_);                      } \
+  } while (0)
 
 MODULE = Math::Prime::Util	PACKAGE = Math::Prime::Util
 
@@ -171,9 +187,14 @@ PROTOTYPES: ENABLE
 
 BOOT:
 {
+    int i;
     SV * sv = newSViv(BITS_PER_WORD);
     HV * stash = gv_stashpv("Math::Prime::Util", TRUE);
     newCONSTSUB(stash, "_XS_prime_maxbits", sv);
+    for (i = 0; i <= 3; i++) {
+      const_int[i] = newSViv(i-1);
+      SvREADONLY_on(const_int[i]);
+    }
 }
 
 void
@@ -191,7 +212,7 @@ prime_memfree()
       case 2:  ret = _XS_get_verbose(); break;
       case 3:  ret = _XS_get_callgmp(); break;
       case 4:
-      default:  ret = get_prime_cache(0,0); break;
+      default: ret = get_prime_cache(0,0); break;
     }
     XSRETURN_UV(ret);
     return_nothing:
@@ -241,7 +262,7 @@ prime_count(IN SV* svlo, ...)
       }
       XSRETURN_UV(count);
     }
-    _vcallsubn(aTHX_ GIMME_V, "_generic_prime_count", items);
+    _vcallsubn(aTHX_ GIMME_V, 0, "_generic_prime_count", items);
     return; /* skip implicit PUTBACK */
 
 UV
@@ -382,13 +403,10 @@ is_strong_pseudoprime(IN SV* svn, ...)
           ret = _XS_miller_rabin(n, bases, b);
         }
       }
-      XSRETURN_UV(ret);
-    } else {
-      const char* sub = _XS_get_callgmp() ? "GMP::is_strong_pseudoprime"
-                                          : "_generic_is_strong_pseudoprime";
-      _vcallsubn(aTHX_ G_SCALAR, sub, items);
-      return; /* skip implicit PUTBACK */
+      RETURN_NPARITY(ret);
     }
+    _vcallsub_with_gmp("is_strong_pseudoprime");
+    return; /* skip implicit PUTBACK */
 
 void
 _XS_lucas_sequence(IN UV n, IN IV P, IN IV Q, IN UV k)
@@ -400,59 +418,58 @@ _XS_lucas_sequence(IN UV n, IN IV P, IN IV Q, IN UV k)
     PUSHs(sv_2mortal(newSVuv( V )));
     PUSHs(sv_2mortal(newSVuv( Qk )));
 
-int
-_XS_is_lucas_pseudoprime(IN UV n, ...)
-  ALIAS:
-    _XS_is_strong_lucas_pseudoprime = 1
-    _XS_is_extra_strong_lucas_pseudoprime = 2
-    _XS_is_frobenius_underwood_pseudoprime = 3
-    _XS_is_almost_extra_strong_lucas_pseudoprime = 4
-    _XS_is_pseudoprime = 5
-    _XS_is_aks_prime = 6
-    _XS_BPSW = 7
-  PREINIT:
-    int ret;
-  CODE:
-    switch (ix) {
-      case 0: ret = _XS_is_lucas_pseudoprime(n, 0); break;
-      case 1: ret = _XS_is_lucas_pseudoprime(n, 1); break;
-      case 2: ret = _XS_is_lucas_pseudoprime(n, 2); break;
-      case 3: ret = _XS_is_frobenius_underwood_pseudoprime(n); break;
-      case 4: ret = _XS_is_almost_extra_strong_lucas_pseudoprime
-                    ( n, (items == 1) ? 1 : my_svuv(ST(1)) );  break;
-      case 5: ret = _XS_is_pseudoprime(n, my_svuv(ST(1)));     break;
-      case 6: ret = _XS_is_aks_prime(n); break;
-      default:ret = _XS_BPSW(n); break;
-    }
-    RETVAL = ret;
-  OUTPUT:
-    RETVAL
-
-
 void
-is_prime(IN SV* svn)
+is_prime(IN SV* svn, ...)
   ALIAS:
     is_prob_prime = 1
+    is_bpsw = 2
+    is_lucas_pseudoprime = 3
+    is_strong_lucas_pseudoprime = 4
+    is_extra_strong_lucas_pseudoprime = 5
+    is_frobenius_underwood_pseudoprime = 6
+    is_aks_prime = 7
+    is_pseudoprime = 8
+    is_almost_extra_strong_lucas_pseudoprime = 9
   PREINIT:
     int status;
   PPCODE:
     status = _validate_int(aTHX_ svn, 1);
-    if (status == -1) {
-      XSRETURN_UV(0);
-    } else if (status == 1) {
-      UV n = my_svuv(svn);
-      XSRETURN_UV(_XS_is_prime(n));
-    } else {
-      const char* sub = 0;
-      if (_XS_get_callgmp())
-        sub = (ix == 0) ? "GMP::is_prime"
-                        : "GMP::is_prob_prime";
-      else
-        sub = (ix == 0) ? "_generic_is_prime"
-                        : "_generic_is_prob_prime";
-      _vcallsub(sub);
-      return; /* skip implicit PUTBACK */
+    if (status != 0) {
+      int ret = 0;
+      if (status == 1) {
+        UV n = my_svuv(svn);
+        UV a = (items == 1) ? 0 : my_svuv(ST(1));
+        switch (ix) {
+          case 0:
+          case 1:  ret = _XS_is_prime(n);  break;
+          case 2:  ret = _XS_BPSW(n);      break;
+          case 3:  ret = _XS_is_lucas_pseudoprime(n, 0); break;
+          case 4:  ret = _XS_is_lucas_pseudoprime(n, 1); break;
+          case 5:  ret = _XS_is_lucas_pseudoprime(n, 2); break;
+          case 6:  ret = _XS_is_frobenius_underwood_pseudoprime(n); break;
+          case 7:  ret = _XS_is_aks_prime(n); break;
+          case 8:  ret = _XS_is_pseudoprime(n, (items == 1) ? 2 : a); break;
+          case 9:
+          default: ret = _XS_is_almost_extra_strong_lucas_pseudoprime
+                         (n, (items == 1) ? 1 : a); break;
+        }
+      }
+      RETURN_NPARITY(ret);
     }
+    switch (ix) {
+      case 0: _vcallsub_with_gmp("is_prime");       break;
+      case 1:
+      case 2: _vcallsub_with_gmp("is_prob_prime");  break;
+      case 3: _vcallsub_with_gmp("is_lucas_pseudoprime"); break;
+      case 4: _vcallsub_with_gmp("is_strong_lucas_pseudoprime"); break;
+      case 5: _vcallsub_with_gmp("is_extra_strong_lucas_pseudoprime"); break;
+      case 6: _vcallsub_with_gmp("is_frobenius_underwood_pseudoprime"); break;
+      case 7: _vcallsub_with_gmp("is_aks_prime"); break;
+      case 8: _vcallsub_with_gmp("is_pseudoprime"); break;
+      case 9:
+      default:_vcallsub_with_gmp("is_almost_extra_strong_lucas_pseudoprime"); break;
+    }
+    return; /* skip implicit PUTBACK */
 
 void
 next_prime(IN SV* svn)
@@ -535,9 +552,9 @@ factor(IN SV* svn)
       }
     } else {
       switch (ix) {
-        case 0:  _vcallsubn(aTHX_ gimme_v, "_generic_factor", 1);     break;
-        case 1:  _vcallsubn(aTHX_ gimme_v, "_generic_factor_exp", 1); break;
-        default: _vcallsubn(aTHX_ gimme_v, "_generic_divisors", 1);   break;
+        case 0:  _vcallsubn(aTHX_ gimme_v, 0, "_generic_factor", 1);     break;
+        case 1:  _vcallsubn(aTHX_ gimme_v, 0, "_generic_factor_exp", 1); break;
+        default: _vcallsubn(aTHX_ gimme_v, 0, "_generic_divisors", 1);   break;
       }
       return; /* skip implicit PUTBACK */
     }
@@ -555,7 +572,7 @@ divisor_sum(IN SV* svn, ...)
       UV sigma = divisor_sum(n, k);
       if (sigma != 0)  XSRETURN_UV(sigma);   /* sigma 0 means overflow */
     }
-    _vcallsubn(aTHX_ G_SCALAR, "_generic_divisor_sum",items);
+    _vcallsub("_generic_divisor_sum");
     return; /* skip implicit PUTBACK */
 
 
@@ -580,9 +597,9 @@ znorder(IN SV* sva, IN SV* svn)
       XSRETURN_UV(ret);
     }
     switch (ix) {
-      case 0:  _vcallsubn(aTHX_ G_SCALAR, "_generic_znorder", 2);  break;
+      case 0:  _vcallsub("_generic_znorder");  break;
       /* TODO: Fixup public PP legendre_phi */
-      default: _vcallsubn(aTHX_ G_SCALAR, "PP::_legendre_phi", 2); break;
+      default: _vcallsub("PP::_legendre_phi"); break;
     }
     return; /* skip implicit PUTBACK */
 
@@ -602,10 +619,10 @@ kronecker(IN SV* sva, IN SV* svb)
     if (abpositive || abnegative) {
       UV a = my_svuv(sva);
       UV b = my_svuv(svb);
-      IV k = (abpositive) ? kronecker_uu(a,b) : kronecker_ss(a,b);
-      XSRETURN_IV( k );
+      int k = (abpositive) ? kronecker_uu(a,b) : kronecker_ss(a,b);
+      RETURN_NPARITY(k);
     }
-    _vcallsubn(aTHX_ G_SCALAR, "_generic_kronecker", 2);
+    _vcallsub("_generic_kronecker");
     return; /* skip implicit PUTBACK */
 
 double
@@ -656,7 +673,7 @@ euler_phi(IN SV* svlo, ...)
         XSRETURN_UV(totient(n));
       } else {
         UV n = (lostatus == -1) ? (UV)(-(my_sviv(svlo))) : my_svuv(svlo);
-        XSRETURN_IV(moebius(n));
+        RETURN_NPARITY(moebius(n));
       }
     } else if (items == 2 && lostatus == 1 && histatus == 1) {
       /* input is a range and both lo and hi are non-negative */
@@ -672,8 +689,9 @@ euler_phi(IN SV* svlo, ...)
           Safefree(totients);
         } else {
           signed char* mu = _moebius_range(lo, hi);
+          /* TODO: assert these are -1,0,1 */
           for (i = lo; i <= hi; i++)
-            PUSHs(sv_2mortal(newSViv(mu[i-lo])));
+            PUSHs(const_int[mu[i-lo]+1]);
           Safefree(mu);
         }
       }
@@ -681,9 +699,9 @@ euler_phi(IN SV* svlo, ...)
       /* Whatever we didn't handle above */
       U32 gimme_v = GIMME_V;
       switch (ix) {
-        case 0:  _vcallsubn(aTHX_ gimme_v, "_generic_euler_phi", items); break;
+        case 0:  _vcallsubn(aTHX_ gimme_v, 0,"_generic_euler_phi", items);break;
         case 1:
-        default: _vcallsubn(aTHX_ gimme_v, "_generic_moebius", items);   break;
+        default: _vcallsubn(aTHX_ gimme_v, 0,"_generic_moebius", items);  break;
       }
       return;
     }
@@ -765,7 +783,7 @@ forprimes (SV* block, IN SV* svbeg, IN SV* svend = 0)
   PPCODE:
   {
 #if !USE_MULTICALL
-    _vcallsubn(aTHX_ G_VOID|G_DISCARD, "_generic_forprimes",items);
+    _vcallsubn(aTHX_ G_VOID|G_DISCARD, 0, "_generic_forprimes", items);
 #else
     UV beg, end;
     GV *gv;
@@ -777,7 +795,7 @@ forprimes (SV* block, IN SV* svbeg, IN SV* svend = 0)
     UV seg_base, seg_low, seg_high;
 
     if (!_validate_int(aTHX_ svbeg, 0) || (items >= 3 && !_validate_int(aTHX_ svend,0))) {
-      _vcallsubn(aTHX_ G_VOID|G_DISCARD, "_generic_forprimes",items);
+      _vcallsubn(aTHX_ G_VOID|G_DISCARD, 0, "_generic_forprimes", items);
       return;
     }
     if (items < 3) {
@@ -867,7 +885,7 @@ forcomposites (SV* block, IN SV* svbeg, IN SV* svend = 0)
       croak("Not a subroutine reference");
 
     if (!_validate_int(aTHX_ svbeg, 0) || (items >= 3 && !_validate_int(aTHX_ svend,0))) {
-      _vcallsubn(aTHX_ G_VOID|G_DISCARD, "_generic_forcomposites",items);
+      _vcallsubn(aTHX_ G_VOID|G_DISCARD, 0, "_generic_forcomposites", items);
       return;
     }
 
@@ -947,7 +965,7 @@ fordivisors (SV* block, IN SV* svn)
       croak("Not a subroutine reference");
 
     if (!_validate_int(aTHX_ svn, 0)) {
-      _vcallsubn(aTHX_ G_VOID|G_DISCARD, "_generic_fordivisors",2);
+      _vcallsubn(aTHX_ G_VOID|G_DISCARD, 0, "_generic_fordivisors", 2);
       return;
     }
 
diff --git a/lib/Math/Prime/Util.pm b/lib/Math/Prime/Util.pm
index d98036e..3dd58e1 100644
--- a/lib/Math/Prime/Util.pm
+++ b/lib/Math/Prime/Util.pm
@@ -59,10 +59,6 @@ sub import {
 
 sub _import_nobigint {
   $_Config{'nobigint'} = 1;
-  return unless $_Config{'xs'};
-  undef *is_pseudoprime;  *is_pseudoprime    = \&_XS_is_pseudoprime;
-  undef *chebyshev_theta; *chebyshev_theta   = \&_XS_chebyshev_theta;
-  undef *chebyshev_psi;   *chebyshev_psi     = \&_XS_chebyshev_psi;
   1;
 }
 
@@ -98,8 +94,16 @@ BEGIN {
     $_Config{'maxbits'} = MPU_MAXBITS;
 
     *_validate_num = \&Math::Prime::Util::PP::_validate_num;
-    *is_prob_prime = \&Math::Prime::Util::_generic_is_prob_prime;
-    *is_prime      = \&Math::Prime::Util::_generic_is_prime;
+    *is_prime      = \&Math::Prime::Util::PP::is_prime;
+    *is_prob_prime = \&Math::Prime::Util::PP::is_prob_prime;
+    *is_pseudoprime=\&Math::Prime::Util::PP::is_pseudoprime;
+    *is_strong_pseudoprime=\&Math::Prime::Util::PP::is_strong_pseudoprime;
+    *is_lucas_pseudoprime=\&Math::Prime::Util::PP::is_lucas_pseudoprime;
+    *is_strong_lucas_pseudoprime=\&Math::Prime::Util::PP::is_strong_lucas_pseudoprime;
+    *is_extra_strong_lucas_pseudoprime=\&Math::Prime::Util::PP::is_extra_strong_lucas_pseudoprime;
+    *is_almost_extra_strong_lucas_pseudoprime=\&Math::Prime::Util::PP::is_almost_extra_strong_lucas_pseudoprime;
+    *is_frobenius_underwood_pseudoprime=\&Math::Prime::Util::PP::is_frobenius_underwood_pseudoprime;
+    *is_aks_prime  =\&Math::Prime::Util::PP::is_aks_prime;
     *next_prime    = \&Math::Prime::Util::_generic_next_prime;
     *prev_prime    = \&Math::Prime::Util::_generic_prev_prime;
     *exp_mangoldt  = \&Math::Prime::Util::_generic_exp_mangoldt;
@@ -114,7 +118,6 @@ BEGIN {
     *znorder       = \&Math::Prime::Util::_generic_znorder;
     *znprimroot    = \&Math::Prime::Util::_generic_znprimroot;
     *legendre_phi  = \&Math::Prime::Util::PP::_legendre_phi;
-    *is_strong_pseudoprime=\&Math::Prime::Util::_generic_is_strong_pseudoprime;
     *factor        = \&Math::Prime::Util::_generic_factor;
     *factor_exp    = \&Math::Prime::Util::_generic_factor_exp;
     *divisors      = \&Math::Prime::Util::_generic_divisors;
@@ -205,7 +208,6 @@ sub prime_set_config {
       _XS_set_callgmp($_HAVE_GMP) if $_Config{'xs'};
     } elsif ($param eq 'nobigint') {
       $_Config{'nobigint'} = ($value) ? 1 : 0;
-      # TODO: Actually make this turn it on or off.
     } elsif ($param eq 'irand') {
       croak "irand must supply a sub" unless (!defined $value) || (ref($value) eq 'CODE');
       $_Config{'irand'} = $value;
@@ -941,7 +943,7 @@ sub primes {
           }
           # We know we don't have GMP and are > 2^64, so skip all the middle.
           #next unless is_prob_prime($p);
-          next unless Math::Prime::Util::PP::miller_rabin($p, 2);
+          next unless Math::Prime::Util::PP::is_strong_pseudoprime($p, 2);
           next unless Math::Prime::Util::PP::is_extra_strong_lucas_pseudoprime($p);
         }
         return $p;
@@ -1567,43 +1569,6 @@ sub _generic_znprimroot {
 # based on the input (XS, GMP, PP).
 #############################################################################
 
-# Doing a sub here like:
-#
-#   sub foo {  my($n) = @_;  _validate_positive_integer($n);
-#              return _XS_... if $n <= $_XS_MAXVAL; }
-#
-# takes about 0.7uS on my machine.  Operations like is_prime and factor run
-# on small inputs typically take a lot less time than this.  So the overhead
-# for these is significantly more than just the XS call itself.  For some
-# functions we have inverted the operation, so the XS function gets called,
-# does validation, and calls the _generic_* sub here if it doesn't know what
-# to do.  This removes all the overhead, making functions like is_prime run
-# about 5x faster for very small inputs.
-
-sub _generic_is_prime {
-  my($n) = @_;
-  return 0 if defined $n && $n < 2;
-  _validate_num($n) || _validate_positive_integer($n);
-
-  return Math::Prime::Util::GMP::is_prime($n) if $_HAVE_GMP;
-
-  if ($n < 7) { return ($n == 2) || ($n == 3) || ($n == 5) ? 2 : 0; }
-  return 0 if !($n % 2) || !($n % 3) || !($n % 5);
-  return Math::Prime::Util::PP::_is_prime7($n);
-}
-
-sub _generic_is_prob_prime {
-  my($n) = @_;
-  return 0 if defined $n && $n < 2;
-  _validate_num($n) || _validate_positive_integer($n);
-
-  return Math::Prime::Util::GMP::is_prob_prime($n) if $_HAVE_GMP;
-
-  if ($n < 7) { return ($n == 2) || ($n == 3) || ($n == 5) ? 2 : 0; }
-  return 0 if !($n % 2) || !($n % 3) || !($n % 5);
-  return Math::Prime::Util::PP::_is_prime7($n);
-}
-
 sub _generic_next_prime {
   my($n) = @_;
   _validate_num($n) || _validate_positive_integer($n);
@@ -1723,84 +1688,6 @@ sub _generic_divisors {
 }
 
 
-sub is_pseudoprime {
-  my($n, $a) = @_;
-  _validate_num($n) || _validate_positive_integer($n);
-  _validate_num($a) || _validate_positive_integer($a);
-  return _XS_is_pseudoprime($n, $a)
-    if $n <= $_XS_MAXVAL;
-  return Math::Prime::Util::GMP::is_pseudoprime($n, $a)
-    if $_HAVE_GMP && defined &Math::Prime::Util::GMP::is_pseudoprime;
-  return Math::Prime::Util::PP::is_pseudoprime($n, $a);
-}
-
-sub _generic_is_strong_pseudoprime {
-  my($n) = shift;
-  _validate_num($n) || _validate_positive_integer($n);
-  # validate bases?
-  return Math::Prime::Util::GMP::is_strong_pseudoprime($n, @_) if $_HAVE_GMP;
-  return Math::Prime::Util::PP::miller_rabin($n, @_);
-}
-
-sub is_lucas_pseudoprime {
-  my($n) = shift;
-  _validate_num($n) || _validate_positive_integer($n);
-  return _XS_is_lucas_pseudoprime($n)
-    if $n <= $_XS_MAXVAL;
-  return Math::Prime::Util::GMP::is_lucas_pseudoprime("$n")
-    if $_HAVE_GMP && defined &Math::Prime::Util::GMP::is_lucas_pseudoprime;
-  return Math::Prime::Util::PP::is_lucas_pseudoprime($n);
-}
-
-sub is_strong_lucas_pseudoprime {
-  my($n) = shift;
-  _validate_num($n) || _validate_positive_integer($n);
-  return _XS_is_strong_lucas_pseudoprime($n)
-    if $n <= $_XS_MAXVAL;
-  return Math::Prime::Util::GMP::is_strong_lucas_pseudoprime("$n")
-    if $_HAVE_GMP;
-  return Math::Prime::Util::PP::is_strong_lucas_pseudoprime($n);
-}
-
-sub is_extra_strong_lucas_pseudoprime {
-  my($n) = shift;
-  _validate_num($n) || _validate_positive_integer($n);
-  return _XS_is_extra_strong_lucas_pseudoprime($n)
-    if $n <= $_XS_MAXVAL;
-  return Math::Prime::Util::GMP::is_extra_strong_lucas_pseudoprime("$n")
-    if $_HAVE_GMP
-    && defined &Math::Prime::Util::GMP::is_extra_strong_lucas_pseudoprime;
-  return Math::Prime::Util::PP::is_extra_strong_lucas_pseudoprime($n);
-}
-
-sub is_almost_extra_strong_lucas_pseudoprime {
-  my($n, $inc) = @_;
-  _validate_num($n) || _validate_positive_integer($n);
-  if (!defined $inc) {
-    $inc = 1;
-  } elsif ($inc ne '1' && $inc ne '2') {
-    (_validate_num($inc) && $inc > 0 && $inc < 257)
-    || _validate_positive_integer($inc, 1, 256);
-  }
-  return _XS_is_almost_extra_strong_lucas_pseudoprime($n, $inc)
-    if $n <= $_XS_MAXVAL;
-  return Math::Prime::Util::GMP::is_almost_extra_strong_lucas_pseudoprime("$n", $inc)
-    if $_HAVE_GMP
-    && defined &Math::Prime::Util::GMP::is_almost_extra_strong_lucas_pseudoprime;
-  return Math::Prime::Util::PP::is_almost_extra_strong_lucas_pseudoprime($n, $inc);
-}
-
-sub is_frobenius_underwood_pseudoprime {
-  my($n) = shift;
-  _validate_num($n) || _validate_positive_integer($n);
-  return _XS_is_frobenius_underwood_pseudoprime($n)
-    if $n <= $_XS_MAXVAL;
-  return Math::Prime::Util::GMP::is_frobenius_underwood_pseudoprime("$n")
-    if $_HAVE_GMP
-    && defined &Math::Prime::Util::GMP::is_frobenius_underwood_pseudoprime;
-  return Math::Prime::Util::PP::is_frobenius_underwood_pseudoprime($n);
-}
-
 sub lucas_sequence {
   my($n, $P, $Q, $k) = @_;
   _validate_num($n) || _validate_positive_integer($n);
@@ -1856,35 +1743,6 @@ sub miller_rabin_random {
 
 #############################################################################
 
-  # Simple timings, with 0.32 code (Montgomery Reduction for 64-bit)
-  # my $n=2**20+1;  do { is_strong_pseudoprime($n,2); $n+=2 } for 1..1000000;
-  # my $n=2**47+1;  do { is_strong_pseudoprime($n,2); $n+=2 } for 1..1000000;
-  #
-  #      1.0 uS  XS 32-bit input, is_strong_pseudoprime
-  #      1.8 uS  XS 64-bit input, is_strong_pseudoprime
-  #      1.3 uS  XS 32-bit input, is_strong_lucas_pseudoprime
-  #      1.9 uS  XS 64-bit input, is_strong_lucas_pseudoprime
-  #      1.2 uS  XS 32-bit input, is_almost_extra_strong_lucas_pseudoprime
-  #      1.8 uS  XS 64-bit input, is_almost_extra_strong_lucas_pseudoprime
-  #
-  #     13 uS  Perl 32-bit input, is_strong_pseudoprime
-  #    945 uS  Perl 64-bit input, is_strong_pseudoprime
-  #   1700 uS  Perl 32-bit input, is_strong_lucas_pseudoprime
-  #   3000 uS  Perl 64-bit input, is_strong_lucas_pseudoprime
-  #   1500 uS  Perl 32-bit input, is_almost_extra_strong_lucas_pseudoprime
-  #   3400 uS  Perl 64-bit input, is_almost_extra_strong_lucas_pseudoprime
-
-sub is_aks_prime {
-  my($n) = @_;
-  return 0 if defined $n && $n < 2;
-  _validate_num($n) || _validate_positive_integer($n);
-
-  return _XS_is_aks_prime($n) if $n <= $_XS_MAXVAL;
-  return Math::Prime::Util::GMP::is_aks_prime($n) if $_HAVE_GMP
-                       && defined &Math::Prime::Util::GMP::is_aks_prime;
-  return Math::Prime::Util::PP::is_aks_prime($n);
-}
-
 # For stripping off the header on certificates so they can be combined.
 sub _strip_proof_header {
   my $proof = shift;
@@ -2530,14 +2388,6 @@ By default all functions support bignums.  For performance, you should
 install and use L<Math::BigInt::GMP> or L<Math::BigInt::Pari>, and
 L<Math::Prime::Util::GMP>.
 
-Using the flag C<-bigint>, e.g.
-
-  use Math::Prime::Util qw(-bigint);
-
-will turn off bigint support for some functions.  This turns off input
-validation and some complicated conversions.  It is not recommended and
-will likely go away in future version.
-
 If you are using bigints, here are some performance suggestions:
 
 =over 4
@@ -2568,7 +2418,9 @@ and are able to provide higher accuracy.
 I have run these functions on many versions of Perl, and my experience is that
 if you're using anything older than Perl 5.14, I would recommend you upgrade
 if you are using bignums a lot.  There are some brittle behaviors on 5.12.4
-and earlier with bignums.
+and earlier with bignums.  For example, the default BigInt backend in older
+versions of Perl will sometimes convert small results to doubles, resulting
+in corrupted output.
 
 =back
 
@@ -3353,7 +3205,7 @@ for large inputs.  For example, computing Mertens(100M) takes:
 
    time    approx mem
      0.4s      0.1MB   mertens(100_000_000)
-     6s     4000MB     List::Util::sum(moebius(1,100_000_000))
+     4s      890MB     List::Util::sum(moebius(1,100_000_000))
     89s        0MB     $sum += moebius($_) for 1..100_000_000
 
 The summation of individual terms via factoring is quite expensive in time,
@@ -3381,7 +3233,7 @@ Returns φ(n), the Euler totient function (also called Euler's phi or phi
 function) for an integer value.  This is an arithmetic function that counts
 the number of positive integers less than or equal to C<n> that are relatively
 prime to C<n>.  Given the definition used, C<euler_phi> will return 0 for all
-C<n E<lt> 1>.  This follows the logic used by SAGE.  Mathematic/WolframAlpha
+C<n E<lt> 1>.  This follows the logic used by SAGE.  Mathematica
 also returns 0 for input 0, but returns C<euler_phi(-n)> for C<n E<lt> 0>.
 
 If called with two arguments, they define a range C<low> to C<high>, and the
@@ -3408,7 +3260,7 @@ the Dedikind psi function, where C<psi(n) = J(2,n) / J(1,n)>.
 
 Returns EXP(Λ(n)), the exponential of the Mangoldt function (also known
 as von Mangoldt's function) for an integer value.
-It is equal to log p if n is prime or a power of a prime,
+The Mangoldt function is equal to log p if n is prime or a power of a prime,
 and 0 otherwise.  We return the exponential so all results are integers.
 Hence the return value for C<exp_mangoldt> is:
 
@@ -3681,9 +3533,10 @@ digits between 1 and the maximum native type (10 for 32-bit, 20 for 64-bit,
 C<irand> function as described above.
 
 If the number of digits is greater than or equal to the maximum native type,
-then the result will be returned as a BigInt.  However, if the C<-nobigint>
-tag was used, then numbers larger than the threshold will be flagged as an
-error, and numbers on the threshold will be restricted to native numbers.
+then the result will be returned as a BigInt.  However, if the C<nobigint>
+configuration option is on, then output will be restricted to native size
+numbers, and requests for more digits than natively supported will result
+in an error.
 For better performance with large bit sizes, install L<Math::Prime::Util::GMP>.
 
 
@@ -4268,7 +4121,7 @@ Here is the right way to do PE problem 69 (under 0.03s):
 
 Project Euler, problem 187, stupid brute force solution, ~4 minutes:
 
-  use Math::Prime::Util qw/factor -nobigint/;
+  use Math::Prime::Util qw/factor/;
   my $nsemis = 0;
   do { $nsemis++ if scalar factor($_) == 2; }
      for 1 .. int(10**8)-1;
@@ -4326,8 +4179,8 @@ is implementation specific (currently it is identical, but later
 releases may use APRCL).  With L<Math::Prime::Util::GMP> installed,
 this is quite fast through 300 or so digits.
 
-Math systems 30 years ago used to use Miller-Rabin tests with C<k>
-bases (typically fixed bases, sometimes random) for primality
+Math systems 30 years ago typically used Miller-Rabin tests with C<k>
+bases (usually fixed bases, sometimes random) for primality
 testing, but these have generally been replaced by some form of BPSW
 as used in this module.  See Pinch's 1993 paper for examples of why
 using C<k> M-R tests leads to poor results.  The three exceptions in
@@ -4383,13 +4236,13 @@ are completely oblivious to what is happening.
 
 =head1 LIMITATIONS
 
-Perl versions earlier than 5.8.0 have a rather broken 64-bit implementation,
-in that the values are accessed as doubles.  Hence any value larger
-than C<~ 2^49> will start losing bottom bits.  This causes numerous functions
-to not work properly.  The test suite will try to determine if your Perl is
-broken (this only applies to really old versions of Perl compiled for 64-bit
-when using numbers larger than C<~ 2^49>).  The best solution is updating to
-a more recent Perl.
+Perl versions earlier than 5.8.0 have problems doing exact integer math.
+Some operations will flip signs, and many operations will convert intermediate
+or output results to doubles, which loses precision on 64-bit systems.
+This causes numerous functions to not work properly.  The test suite will
+try to determine if your Perl is broken (this only applies to really old
+versions of Perl compiled for 64-bit when using numbers larger than
+C<~ 2^49>).  The best solution is updating to a more recent Perl.
 
 The module is thread-safe and should allow good concurrency on all platforms
 that support Perl threads except Win32.  With Win32, either don't use threads
@@ -4431,9 +4284,8 @@ handle using it.  There are still some functions it doesn't do well
 L<Math::Prime::XS> has C<is_prime> and C<primes> functionality.  There is
 no bigint support.  The C<is_prime> function uses well-written trial
 division, meaning it is very fast for small numbers, but terribly slow for
-large 64-bit numbers.  Because MPU does input validation and bigint
-conversion, there is about 20 microseconds of additional overhead making
-MPXS a little faster for tiny inputs, but once over ~700k MPU is faster.
+large 64-bit numbers.  MPU is similarly fast with small numbers, but becomes
+faster as the size increases.
 MPXS's prime sieve is an unoptimized non-segmented SoE
 which returns an array.  Sieve bases larger than C<10^7> start taking
 inordinately long and using a lot of memory (gigabytes beyond C<10^10>).
@@ -4599,7 +4451,7 @@ L<divisor_sum>.
 =item C<eulerphi>, C<moebius>
 
 Similar to MPU's L</euler_phi> and L</moebius>.  MPU is 2-20x faster for
-native integers.  There is also support for a range, which can be much
+native integers.  MPU also supported range inputs, which can be much
 more efficient.  Without L<Math::Prime::Util::GMP> installed, MPU is
 very slow with bigints.  With it installed, it is about 2x slower than
 Math::Pari.
diff --git a/lib/Math/Prime/Util/PP.pm b/lib/Math/Prime/Util/PP.pm
index 7e1e3ef..169c8a3 100644
--- a/lib/Math/Prime/Util/PP.pm
+++ b/lib/Math/Prime/Util/PP.pm
@@ -189,7 +189,7 @@ sub _is_prime7 {  # n must not be divisible by 2, 3, or 5
     elsif ($n <   47636622961201) { @bases = ( 2, 2570940, 211991001, 3749873356); }
     elsif ($n < 3770579582154547) { @bases = ( 2, 2570940, 880937, 610386380, 4130785767); }
     else                          { @bases = ( 2, 325, 9375, 28178, 450775, 9780504, 1795265022); }
-    return miller_rabin($n, @bases)  ?  2  :  0;
+    return is_strong_pseudoprime($n, @bases)  ?  2  :  0;
   }
 
   # BPSW probable prime.  No composites are known to have passed this test
@@ -197,7 +197,7 @@ sub _is_prime7 {  # n must not be divisible by 2, 3, or 5
   # It has also been verified that no 64-bit composite will return true.
   # Slow since it's all in PP and uses bigints.
 
-  return 0 unless miller_rabin($n, 2);
+  return 0 unless is_strong_pseudoprime($n, 2);
   if ($n <= 18446744073709551615) {
     return is_almost_extra_strong_lucas_pseudoprime($n) ? 2 : 0;
   }
@@ -206,14 +206,17 @@ sub _is_prime7 {  # n must not be divisible by 2, 3, or 5
 
 sub is_prime {
   my($n) = @_;
+  return 0 if defined $n && int($n) < 0;
   _validate_positive_integer($n);
 
-  return 2 if ($n == 2) || ($n == 3) || ($n == 5);  # 2, 3, 5 are prime
-  return 0 if $n < 7;             # everything else below 7 is composite
+  if ($n < 7) { return ($n == 2) || ($n == 3) || ($n == 5) ? 2 : 0; }
   return 0 if !($n % 2) || !($n % 3) || !($n % 5);
   return _is_prime7($n);
 }
 
+# is_prob_prime is the same thing for us.
+*is_prob_prime = \&is_prime;
+
 # Possible sieve storage:
 #   1) vec with mod-30 wheel:   8 bits  / 30
 #   2) vec with mod-2 wheel :  15 bits  / 30
@@ -933,11 +936,11 @@ sub _order {
 
 sub is_pseudoprime {
   my($n, $base) = @_;
+  return 0 if defined $n && int($n) < 0;
   _validate_positive_integer($n);
   _validate_positive_integer($base);
 
-  return 1 if $n == 2 || $n == 3;
-  return 0 if $n < 5;
+  if ($n < 5) { return ($n == 2) || ($n == 3) ? 1 : 0; }
   croak "Base $base is invalid" if $base < 2;
   if ($base >= $n) {
     $base = $base % $n;
@@ -949,8 +952,9 @@ sub is_pseudoprime {
   return ($x == 1) ? 1 : 0;
 }
 
-sub miller_rabin {
+sub is_strong_pseudoprime {
   my($n, @bases) = @_;
+  return 0 if defined $n && int($n) < 0;
   _validate_positive_integer($n);
   croak "No bases given to miller_rabin" unless @bases;
 
@@ -1212,6 +1216,7 @@ sub lucas_sequence {
 
 sub is_lucas_pseudoprime {
   my($n) = @_;
+  return 0 if defined $n && int($n) < 0;
   _validate_positive_integer($n);
 
   return 1 if $n == 2;
@@ -1228,6 +1233,7 @@ sub is_lucas_pseudoprime {
 
 sub is_strong_lucas_pseudoprime {
   my($n) = @_;
+  return 0 if defined $n && int($n) < 0;
   _validate_positive_integer($n);
 
   return 1 if $n == 2;
@@ -1259,6 +1265,7 @@ sub is_strong_lucas_pseudoprime {
 
 sub is_extra_strong_lucas_pseudoprime {
   my($n) = @_;
+  return 0 if defined $n && int($n) < 0;
   _validate_positive_integer($n);
 
   return 1 if $n == 2;
@@ -1290,9 +1297,13 @@ sub is_extra_strong_lucas_pseudoprime {
 
 sub is_almost_extra_strong_lucas_pseudoprime {
   my($n, $increment) = @_;
+  return 0 if defined $n && int($n) < 0;
   _validate_positive_integer($n);
-  $increment = 1 unless defined $increment;
-  _validate_positive_integer($increment, 1, 256);
+  if (defined $increment) {
+    _validate_positive_integer($increment, 1, 256);
+  } else {
+    $increment = 1;
+  }
 
   return 1 if $n == 2;
   return 0 if $n < 2 || ($n % 2) == 0;
@@ -1331,6 +1342,7 @@ sub is_almost_extra_strong_lucas_pseudoprime {
 
 sub is_frobenius_underwood_pseudoprime {
   my($n) = @_;
+  return 0 if defined $n && int($n) < 0;
   _validate_positive_integer($n);
   return 0 if $n < 2;
   return 1 if $n < 4;
@@ -1449,6 +1461,8 @@ sub _test_anr {
 
 sub is_aks_prime {
   my $n = shift;
+  return 0 if defined $n && int($n) < 0;
+  _validate_positive_integer($n);
 
   $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt';
 
@@ -2851,8 +2865,6 @@ L<OEIS A001567|http://oeis.org/A001567>.
 
 =head2 is_strong_pseudoprime
 
-=head2 miller_rabin
-
   my $maybe_prime = is_strong_pseudoprime($n, 2);
   my $probably_prime = is_strong_pseudoprime($n, 2, 3, 5, 7, 11, 13, 17);
 
@@ -3178,7 +3190,7 @@ operations that are relatively close for small and medium-size values:
 
   next_prime / prev_prime
   is_prime / is_prob_prime
-  miller_rabin
+  is_strong_pseudoprime
   ExponentialIntegral / LogarithmicIntegral / RiemannR
   primearray
 
diff --git a/t/80-pp.t b/t/80-pp.t
index 6e113a3..c8b0c59 100644
--- a/t/80-pp.t
+++ b/t/80-pp.t
@@ -286,7 +286,7 @@ require_ok 'Math::Prime::Util::PrimalityProving';
     *prev_prime     = \&Math::Prime::Util::PP::prev_prime;
 
     *is_pseudoprime = \&Math::Prime::Util::PP::is_pseudoprime;
-    *miller_rabin   = \&Math::Prime::Util::PP::miller_rabin;
+    *is_strong_pseudoprime = \&Math::Prime::Util::PP::is_strong_pseudoprime;
     *is_lucas_pseudoprime = \&Math::Prime::Util::PP::is_lucas_pseudoprime;
     *is_strong_lucas_pseudoprime = \&Math::Prime::Util::PP::is_strong_lucas_pseudoprime;
     *is_extra_strong_lucas_pseudoprime = \&Math::Prime::Util::PP::is_extra_strong_lucas_pseudoprime;
@@ -398,10 +398,10 @@ while (my($n, $nth) = each (%nthprimes_small)) {
 
 ###############################################################################
 
-is( miller_rabin(0, 2), 0, "MR with 0 shortcut composite");
-is( miller_rabin(1, 2), 0, "MR with 0 shortcut composite");
-is( miller_rabin(2, 2), 1, "MR with 2 shortcut prime");
-is( miller_rabin(3, 2), 1, "MR with 3 shortcut prime");
+is( is_strong_pseudoprime(0, 2), 0, "MR with 0 shortcut composite");
+is( is_strong_pseudoprime(1, 2), 0, "MR with 0 shortcut composite");
+is( is_strong_pseudoprime(2, 2), 1, "MR with 2 shortcut prime");
+is( is_strong_pseudoprime(3, 2), 1, "MR with 3 shortcut prime");
 
 while (my($base, $ppref) = each (%pseudoprimes)) {
   my $npseudos = scalar @$ppref;
@@ -420,7 +420,7 @@ while (my($base, $ppref) = each (%pseudoprimes)) {
   } elsif ($base eq 'lucas') {
      @gotmr = map { is_lucas_pseudoprime($_) } @$ppref;
   } else {
-     @gotmr = map { miller_rabin($_, $base) } @$ppref;
+     @gotmr = map { is_strong_pseudoprime($_, $base) } @$ppref;
   }
   is_deeply(\@gotmr, \@expmr, "$npseudos pseudoprimes (base $base)");
 }
@@ -607,8 +607,8 @@ if ($use64) {
 
 {
   my $n = Math::BigInt->new("168790877523676911809192454171451");
-  is( miller_rabin( $n, 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47), 1, "168790877523676911809192454171451 looks prime with bases 2..52" );
-  is( miller_rabin( $n, 53), 0, "168790877523676911809192454171451 found composite with base 53" );
+  is( is_strong_pseudoprime( $n, 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47), 1, "168790877523676911809192454171451 looks prime with bases 2..52" );
+  is( is_strong_pseudoprime( $n, 53), 0, "168790877523676911809192454171451 found composite with base 53" );
   is ( is_strong_lucas_pseudoprime($n), 0, "168790877523676911809192454171451 is not a strong Lucas pseudoprime" );
   SKIP: {
     skip "Old Perl+bigint segfaults in F-U code", 1 if $] < 5.008;
diff --git a/util.c b/util.c
index 2e25b0b..2e24118 100644
--- a/util.c
+++ b/util.c
@@ -200,7 +200,7 @@ int _XS_is_prime(UV n)
   if (n <= 10)
     return (n == 2 || n == 3 || n == 5 || n == 7) ? 2 : 0;
 
-  if (n < UVCONST(2000000000)) {
+  if (n < UVCONST(2000000)) {
     UV d = n/30;
     UV m = n - d*30;
     unsigned char mtab = masktab30[m];  /* Bitmask in mod30 wheel */

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