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

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

commit f246f75cbf60d2086793b6a25c4f5290d879512a
Author: Dana Jacobsen <d...@acm.org>
Date:   Wed Sep 11 15:27:59 2013 -0700

    Move primality functions to new file.  Use Monty routines
---
 .gitignore                        |   1 +
 Changes                           |   9 +-
 MANIFEST                          |   2 +
 Makefile.PL                       |  13 +-
 TODO                              |   9 +-
 XS.xs                             |   3 +
 aks.c                             |   1 -
 factor.c                          | 527 +----------------------------
 factor.h                          |  21 --
 lib/Math/Prime/Util/PrimeArray.pm |   4 +-
 primality.c                       | 689 ++++++++++++++++++++++++++++++++++++++
 primality.h                       |  22 ++
 util.c                            |   2 +-
 util.h                            |  11 +
 xt/primality-small.pl             |   2 +-
 15 files changed, 757 insertions(+), 559 deletions(-)

diff --git a/.gitignore b/.gitignore
index 4681eb4..55be186 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ factor.o
 sieve.o
 util.o
 lehmer.o
+primality.o
 aks.o
 blib*
 b[0-9][0-9][0-9][0-9][0-9][0-9].txt
diff --git a/Changes b/Changes
index 695ed5b..ef8973f 100644
--- a/Changes
+++ b/Changes
@@ -18,7 +18,14 @@ Revision history for Perl module Math::Prime::Util
       Thanks to Kim Walisch for all discussions about this.
 
     - divisor_sum can take a '1' as the second argument as an alias for
-      sub {1}, but works much faster.
+      sub {1}, but works much faster.  (experimental, may change)
+
+    - Incorporate Montgomery reduction for primality testing, thanks to
+      Wojciech Izykowski.  This is a 1.3 to 1.5x speedup for is_prob_prime,
+      is_prime, and is_strong_pseudoprime for numbers > 2^32 on x86_64.
+      This also things like prime_iterator for values > 2^32.
+
+    - Primality functions moved to their own file primality.c.
 
 0.31  2013-08-07
 
diff --git a/MANIFEST b/MANIFEST
index 1b3031f..d16dc1e 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -25,6 +25,8 @@ factor.h
 factor.c
 lehmer.h
 lehmer.c
+primality.h
+primality.c
 sieve.h
 sieve.c
 util.h
diff --git a/Makefile.PL b/Makefile.PL
index b0099c2..2e24249 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -7,12 +7,13 @@ WriteMakefile1(
     LICENSE      => 'perl',
     AUTHOR       => 'Dana A Jacobsen <d...@acm.org>',
 
-    OBJECT       => 'cache.o '  .
-                    'factor.o ' .
-                    'aks.o '    .
-                    'lehmer.o ' .
-                    'sieve.o '  .
-                    'util.o '   .
+    OBJECT       => 'cache.o '    .
+                    'factor.o '   .
+                    'primality.o '.
+                    'aks.o '      .
+                    'lehmer.o '   .
+                    'sieve.o '    .
+                    'util.o '     .
                     'XS.o',
     LIBS         => ['-lm'],
 
diff --git a/TODO b/TODO
index 146dc4c..97bb00f 100644
--- a/TODO
+++ b/TODO
@@ -39,6 +39,11 @@
 - Figure out a way to make the internal FOR_EACH_PRIME macros use a segmented
   sieve.
 
-- Refactor where functions exist in .c.  Lots of primality tests in factor.c.
-
 - Rewrite 23-primality-proofs.t for new format (keep some of the old tests?).
+
+- Use Montgomery routines in more places: Factoring and Lucas tests.
+
+- Add a group order function.  We have a naieve method used in AKS (where the
+  values are so small it doesn't matter).  See:
+  
http://cs-haven.blogspot.com/2012/02/efficiently-computing-order-of-element.html
+  for some discussion of different methods.
diff --git a/XS.xs b/XS.xs
index 2150603..84a7ba3 100644
--- a/XS.xs
+++ b/XS.xs
@@ -14,6 +14,7 @@
 #include "cache.h"
 #include "sieve.h"
 #include "util.h"
+#include "primality.h"
 #include "factor.h"
 #include "lehmer.h"
 #include "aks.h"
@@ -484,6 +485,7 @@ _XS_is_prime(IN UV n)
     _XS_is_extra_strong_lucas_pseudoprime = 4
     _XS_is_frobenius_underwood_pseudoprime = 5
     _XS_is_aks_prime = 6
+    _XS_BPSW = 7
   PREINIT:
     int ret;
   CODE:
@@ -495,6 +497,7 @@ _XS_is_prime(IN UV n)
       case 4: ret = _XS_is_lucas_pseudoprime(n, 2); break;
       case 5: ret = _XS_is_frobenius_underwood_pseudoprime(n); break;
       case 6: ret = _XS_is_aks_prime(n); break;
+      case 7: ret = _XS_BPSW(n); break;
       default: croak("_XS_is_prime: Unknown function alias"); break;
     }
     RETVAL = ret;
diff --git a/aks.c b/aks.c
index ba86e69..119d55b 100644
--- a/aks.c
+++ b/aks.c
@@ -28,7 +28,6 @@
 #include "aks.h"
 #include "util.h"
 #include "sieve.h"
-#include "factor.h"
 #include "cache.h"
 #include "mulmod.h"
 
diff --git a/factor.c b/factor.c
index b7166de..e43f335 100644
--- a/factor.c
+++ b/factor.c
@@ -3,13 +3,14 @@
 #include <string.h>
 #include <math.h>
 
-#define FUNC_gcd_ui
 #include "ptypes.h"
 #include "factor.h"
-#include "util.h"
 #include "sieve.h"
 #include "mulmod.h"
 #include "cache.h"
+#include "primality.h"
+#define FUNC_gcd_ui
+#include "util.h"
 
 /*
  * You need to remember to use UV for unsigned and IV for signed types that
@@ -289,396 +290,6 @@ static int is_perfect_square(UV n, UV* sqrtn)
   return 1;
 }
 
-static int jacobi_iu(IV in, UV m) {
-  int j = 1;
-  UV n = (in < 0) ? -in : in;
-
-  if (m <= 0 || (m%2) == 0) return 0;
-  if (in < 0 && (m%4) == 3) j = -j;
-  while (n != 0) {
-    while ((n % 2) == 0) {
-      n >>= 1;
-      if ( (m % 8) == 3 || (m % 8) == 5 )  j = -j;
-    }
-    { UV t = n; n = m; m = t; }
-    if ( (n % 4) == 3 && (m % 4) == 3 )  j = -j;
-    n = n % m;
-  }
-  return (m == 1) ? j : 0;
-}
-
-
-/* Fermat pseudoprime */
-int _XS_is_pseudoprime(UV n, UV a)
-{
-  UV x;
-  UV const nm1 = n-1;
-
-  if (n == 2 || n == 3)  return 1;
-  if (n < 5) return 0;
-  if (a < 2) croak("Base %"UVuf" is invalid", a);
-  if (a >= n) {
-    a %= n;
-    if ( a <= 1 || a == nm1 )
-      return 1;
-  }
-
-  x = powmod(a, nm1, n);    /* x = a^(n-1) mod n */
-  return (x == 1);
-}
-
-
-/* Miller-Rabin probabilistic primality test
- * Returns 1 if probably prime relative to the bases, 0 if composite.
- * Bases must be between 2 and n-2
- */
-int _XS_miller_rabin(UV n, const UV *bases, int nbases)
-{
-  UV const nm1 = n-1;
-  UV d = n-1;
-  int b, r, s = 0;
-
-  MPUassert(n > 3, "MR called with n <= 3");
-
-  while ( (d&1) == 0 ) {
-    s++;
-    d >>= 1;
-  }
-  for (b = 0; b < nbases; b++) {
-    UV x, a = bases[b];
-
-    if (a < 2)
-      croak("Base %"UVuf" is invalid", a);
-    if (a >= n)
-      a %= n;
-    if ( (a <= 1) || (a == nm1) )
-      continue;
-
-    /* n is a strong pseudoprime to this base if either
-     *   -  a^d = 1 mod n
-     *   -  a^(d2^r) = -1 mod n for some r: 0 <= r <= s-1
-     */
-
-    x = powmod(a, d, n);
-    if ( (x == 1) || (x == nm1) )  continue;
-
-    /* cover r = 1 to s-1, r=0 was just done */
-    for (r = 1; r < s; r++) {
-      x = sqrmod(x, n);
-      if ( x == nm1 )  break;
-      if ( x == 1   )  return 0;
-    }
-    if (r >= s)
-      return 0;
-  }
-  return 1;
-}
-
-/* M-R with a = 2 and some checks removed.  For internal use. */
-int _SPRP2(UV n)
-{
-  UV const nm1 = n-1;
-  UV d = n-1;
-  UV x;
-  int r, s = 0;
-
-  MPUassert(n > 3, "S-PRP-2 called with n <= 3");
-  if (!(n & 1)) return 0;
-  while ( (d & 1) == 0 ) {  s++;  d >>= 1; }
-  /* n is a strong pseudoprime to this base if either
-   *   -  a^d = 1 mod n
-   *   -  a^(d2^r) = -1 mod n for some r: 0 <= r <= s-1 */
-  x = powmod(2, d, n);
-  if (x == 1 || x == nm1)  return 1;
-
-  /* just did r=0, now test r = 1 to s-1 */
-  for (r = 1; r < s; r++) {
-    x = sqrmod(x, n);
-    if (x == nm1)  return 1;
-  }
-  return 0;
-}
-
-/* Select M-R bases from http://miller-rabin.appspot.com/, 27 May 2013 */
-#if BITS_PER_WORD == 32
-static const UV mr_bases_small_2[2] = {31, 73};
-static const UV mr_bases_small_3[3] = {2, 7, 61};
-#else
-static const UV mr_bases_large_1[1] = { UVCONST(  9345883071009581737 ) };
-static const UV mr_bases_large_2[2] = { UVCONST(         336781006125 ),
-                                        UVCONST(     9639812373923155 ) };
-static const UV mr_bases_large_3[3] = { UVCONST(  4230279247111683200 ),
-                                        UVCONST( 14694767155120705706 ),
-                                        UVCONST( 16641139526367750375 ) };
-#endif
-
-int _XS_is_prob_prime(UV n)
-{
-  int ret;
-
-  if (n < 11) {
-    if (n == 2 || n == 3 || n == 5 || n == 7)     return 2;
-    else                                          return 0;
-  }
-  if (!(n%2) || !(n%3) || !(n%5) || !(n%7))       return 0;
-  if (n <  121) /* 11*11 */                       return 2;
-  if (!(n%11) || !(n%13) || !(n%17) || !(n%19) ||
-      !(n%23) || !(n%29) || !(n%31) || !(n%37) ||
-      !(n%41) || !(n%43) || !(n%47) || !(n%53))   return 0;
-  if (n < 3481) /* 59*59 */                       return 2;
-
-#if BITS_PER_WORD == 32
-  /* We could use one base when n < 49191, two when n < 360018361. */
-  if (n < UVCONST(9080191))
-    ret = _XS_miller_rabin(n, mr_bases_small_2, 2);
-  else
-    ret = _XS_miller_rabin(n, mr_bases_small_3, 3);
-#else
-  /* AESLSP test costs about 1.5 Selfridges, vs. ~2.2 for strong Lucas.
-   * So it works out to be faster to do AES-BPSW vs. 3 M-R tests. */
-  if (n < UVCONST(341531))
-    ret = _XS_miller_rabin(n, mr_bases_large_1, 1);
-  else if (n < UVCONST(1050535501))
-    ret = _XS_miller_rabin(n, mr_bases_large_2, 2);
-  else
-    ret = _SPRP2(n) && _XS_is_almost_extra_strong_lucas_pseudoprime(n,1);
-#endif
-  return 2*ret;
-}
-
-/* Generic Lucas sequence for any appropriate P and Q */
-void lucas_seq(UV* Uret, UV* Vret, UV* Qkret, UV n, IV P, IV Q, UV k)
-{
-  UV U, V, b, Dmod, Qmod, Pmod, Qk;
-
-  if (k == 0) {
-    *Uret = 0;
-    *Vret = 2;
-    *Qkret = Q;
-    return;
-  }
-
-  Qmod = (Q < 0)  ?  (UV)(Q + (IV)n)  :  (UV)Q;
-  Pmod = (P < 0)  ?  (UV)(P + (IV)n)  :  (UV)P;
-  Dmod = submod( mulmod(Pmod, Pmod, n), mulmod(4, Qmod, n), n);
-  MPUassert(Dmod != 0, "lucas_seq: D is 0");
-  U = 1;
-  V = Pmod;
-  Qk = Qmod;
-  { UV v = k; b = 1; while (v >>= 1) b++; }
-
-  if (Q == 1) {
-    while (b > 1) {
-      U = mulmod(U, V, n);
-      V = mulsubmod(V, V, 2, n);
-      b--;
-      if ( (k >> (b-1)) & UVCONST(1) ) {
-        UV t2 = mulmod(U, Dmod, n);
-        U = muladdmod(U, Pmod, V, n);
-        if (U & 1) { U = (n>>1) + (U>>1) + 1; } else { U >>= 1; }
-        V = muladdmod(V, P, t2, n);
-        if (V & 1) { V = (n>>1) + (V>>1) + 1; } else { V >>= 1; }
-      }
-    }
-  } else if (P == 1 && Q == -1) {
-    /* This is about 30% faster than the generic code below.  Since 50% of
-     * Lucas and strong Lucas tests come here, I think it's worth doing. */
-    int sign = Q;
-    while (b > 1) {
-      U = mulmod(U, V, n);
-      if (sign == 1) V = mulsubmod(V, V, 2, n);
-      else           V = muladdmod(V, V, 2, n);
-      sign = 1;   /* Qk *= Qk */
-      b--;
-      if ( (k >> (b-1)) & UVCONST(1) ) {
-        UV t2 = mulmod(U, Dmod, n);
-        U = addmod(U, V, n);
-        if (U & 1) { U = (n>>1) + (U>>1) + 1; } else { U >>= 1; }
-        V = addmod(V, t2, n);
-        if (V & 1) { V = (n>>1) + (V>>1) + 1; } else { V >>= 1; }
-        sign = -1;  /* Qk *= Q */
-      }
-    }
-    if (sign == 1) Qk = 1;
-  } else {
-    while (b > 1) {
-      U = mulmod(U, V, n);
-      V = mulsubmod(V, V, addmod(Qk,Qk,n), n);
-      Qk = sqrmod(Qk, n);
-      b--;
-      if ( (k >> (b-1)) & UVCONST(1) ) {
-        UV t2 = mulmod(U, Dmod, n);
-        U = muladdmod(U, Pmod, V, n);
-        if (U & 1) { U = (n>>1) + (U>>1) + 1; } else { U >>= 1; }
-        V = muladdmod(V, P, t2, n);
-        if (V & 1) { V = (n>>1) + (V>>1) + 1; } else { V >>= 1; }
-        Qk = mulmod(Qk, Qmod, n);
-      }
-    }
-  }
-  *Uret = U;
-  *Vret = V;
-  *Qkret = Qk;
-}
-
-/* Lucas tests:
- *  0: Standard
- *  1: Strong
- *  2: Extra Strong (Mo/Jones/Grantham)
- *
- * Goal:
- *       (1) no false results when combined with the SPRP-2 test.
- *       (2) fast enough to use SPRP-2 + this in place of 3+ M-R tests.
- *
- * For internal purposes, we typically want to use the extra strong test
- * because it is slightly faster (Q = 1 simplies things).  None of them have
- * any false positives for the BPSW test.
- *
- * This runs 4-7x faster than MPU::GMP, which means ~10x faster than most GMP
- * implementations.  It is about 2x slower than a single M-R test.
- */
-int _XS_is_lucas_pseudoprime(UV n, int strength)
-{
-  IV P, Q, D;
-  UV U, V, Qk, d, s;
-
-  if (n == 2 || n == 3) return 1;
-  if (n < 5 || (n%2) == 0) return 0;
-  if (n == UV_MAX) return 0;
-
-  if (strength < 2) {
-    UV Du = 5;
-    IV sign = 1;
-    while (1) {
-      D = Du * sign;
-      if (gcd_ui(Du, n) > 1 && gcd_ui(Du, n) != n) return 0;
-      if (jacobi_iu(D, n) == -1)
-        break;
-      if (Du == 21 && is_perfect_square(n, 0)) return 0;
-      Du += 2;
-      sign = -sign;
-    }
-    P = 1;
-    Q = (1 - D) / 4;
-  } else {
-    P = 3;
-    Q = 1;
-    while (1) {
-      D = P*P - 4;
-      if (gcd_ui(D, n) > 1 && gcd_ui(D, n) != n) return 0;
-      if (jacobi_iu(D, n) == -1)
-        break;
-      if (P == 21 && is_perfect_square(n, 0)) return 0;
-      P++;
-    }
-  }
-  MPUassert( D == (P*P - 4*Q) , "is_lucas_pseudoprime: incorrect DPQ");
-
-  d = n+1;
-  s = 0;
-  if (strength > 0)
-    while ( (d & 1) == 0 ) {  s++;  d >>= 1; }
-  lucas_seq(&U, &V, &Qk, n, P, Q, d);
-
-  if (strength == 0) {
-    if (U == 0)
-      return 1;
-  } else if (strength == 1) {
-    if (U == 0)
-      return 1;
-    /* Now check to see if V_{d*2^r} == 0 for any 0 <= r < s */
-    while (s--) {
-      if (V == 0)
-        return 1;
-      if (s) {
-        V = mulsubmod(V, V, addmod(Qk,Qk,n), n);
-        Qk = sqrmod(Qk, n);
-      }
-    }
-  } else {
-    if ( U == 0 && (V == 2 || V == (n-2)) )
-      return 1;
-    /* Now check to see if V_{d*2^r} == 0 for any 0 <= r < s-1 */
-    s--;
-    while (s--) {
-      if (V == 0)
-        return 1;
-      if (s)
-        V = mulsubmod(V, V, 2, n);
-    }
-  }
-  return 0;
-}
-
-/* A generalization of Pari's shortcut to the extra-strong Lucas test.
- * I've added a gcd check at the top, which needs to be done and also results
- * in fewer pseudoprimes.  Pari always does trial division to 100 first so
- * is unlikely to come up there.  This only calculate V, which can be done
- * faster, but that means we have more pseudoprimes than the standard
- * extra-strong test.
- *
- * increment:  1 for Baillie OEIS, 2 for Pari.
- *
- * With increment = 1, these results will be a subset of the extra-strong
- * Lucas pseudoprimes.  With increment = 2, we produce Pari's results.
- */
-int _XS_is_almost_extra_strong_lucas_pseudoprime(UV n, UV increment)
-{
-  UV P, V, d, s;
-
-  if (n == 2 || n == 3 || n == 5) return 1;
-  if (n < 7 || (n%2) == 0) return 0;
-  if (n == UV_MAX) return 0;
-  if (increment < 1 || increment > 256)
-    croak("Invalid lucas paramater increment: %"UVuf"\n", increment);
-
-  P = 3;
-  while (1) {
-    UV D = P*P - 4;
-    d = gcd_ui(D, n);
-    if (d > 1 && d < n)
-      return 0;
-    if (jacobi_iu(D, n) == -1)
-      break;
-    if (P == (3+20*increment) && is_perfect_square(n, 0)) return 0;
-    P += increment;
-    if (P > 65535)
-      croak("lucas_extrastrong_params: P exceeded 65535");
-  }
-  if (P >= n)  P %= n;   /* Never happens with increment < 4 */
-
-  d = n+1;
-  s = 0;
-  while ( (d & 1) == 0 ) {  s++;  d >>= 1; }
-
-  {
-    UV W, b;
-    V = P;
-    W = mulsubmod(P, P, 2, n);
-    { UV v = d; b = 1; while (v >>= 1) b++; }
-    while (b-- > 1) {
-      if ( (d >> (b-1)) & UVCONST(1) ) {
-        V = mulsubmod(V, W, P, n);
-        W = mulsubmod(W, W, 2, n);
-      } else {
-        W = mulsubmod(V, W, P, n);
-        V = mulsubmod(V, V, 2, n);
-      }
-    }
-  }
-
-  if (V == 2 || V == (n-2))
-    return 1;
-  while (s-- > 1) {
-    if (V == 0)
-      return 1;
-    V = mulsubmod(V, V, 2, n);
-    if (V == 2)
-      return 0;
-  }
-  return 0;
-}
-
 
 UV _XS_divisor_sum(UV n)
 {
@@ -1378,135 +989,3 @@ int racing_squfof_factor(UV n, UV *factors, UV rounds)
   factors[0] = n;
   return 1;
 }
-
-
-/****************************************************************************/
-
-/*
- *
- * The Frobenius-Underwood test has no known counterexamples below 10^13, but
- * has not been extensively tested above that.  This is the Minimal Lambda+2
- * test from section 9 of "Quadratic Composite Tests" by Paul Underwood.
- *
- * Given the script:
- *  time mpu 'forprimes { 
Math::Prime::Util::_XS_is_frobenius_underwood_pseudoprime($_); 
Math::Prime::Util::_XS_is_frobenius_underwood_pseudoprime($_+2); } 500_000_000'
- * and replacing the tests appropriately, I get these times:
- *
- *    0.87    $_ (cost of empty loop)
- *   21.37    _XS_is_pseudoprime($_,2)
- *   22.42    _XS_miller_rabin($_,2)
- *   44.53    _XS_is_lucas_pseudoprime($_)
- *   43.95    _XS_is_strong_lucas_pseudoprime($_)
- *   40.09    _XS_is_extra_strong_lucas_pseudoprime($_)
- *   25.86    _XS_is_almost_extra_strong_lucas_pseudoprime($_)
- *   42.40    _XS_is_frobenius_underwood_pseudoprime($_)
- *   27.02    _XS_is_prob_prime($_)
- *   27.24    _XS_is_prime($_)
- *
- * At these sizes is_prob_prime is doing 1-2 M-R tests.  The input validation
- * is adding a noticeable overhead to is_prime.
- *
- * With a set of 100k 64-bit random primes; 'do { die unless ... } for 1..50'
- *
- *   0.32    empty loop
- *  10.25    _XS_is_pseudoprime($_,2)
- *  10.06    _XS_miller_rabin($_,2)
- *  22.02    _XS_is_lucas_pseudoprime($_)
- *  21.81    _XS_is_strong_lucas_pseudoprime($_)
- *  20.99    _XS_is_extra_strong_lucas_pseudoprime($_)
- *  14.01    _XS_is_almost_extra_strong_lucas_pseudoprime($_)
- *  18.44    _XS_is_frobenius_underwood_pseudoprime($_)
- *  24.11    _XS_is_prob_prime($_)
- *  24.06    _XS_is_prime($_)
- *
- * At this point is_prob_prime has transitioned to BPSW.
- *
- * Calling a powmod a 'Selfridge' unit, then we see:
- *    1   Selfridge unit    M-R test
- *    1.4 Selfridge unit    "almost extra strong" Lucas
- *    2   Selfridge units   Lucas or Frobenius-Underwood
- *    3   Selfridge units   BPSW (standard, strong, or extra-strong)
- *
- * We try to structure the primality test like:
- *   1) simple divisibility    very fast       primes and ~10% of composites
- *   2) M-R with base 2        1 Selfridge     primes and .00000000002% comps
- *   3) Lucas test             2 Selfridge     only primes
- *
- * Hence given a random composite, about 90% of the time it costs us almost
- * nothing.  After spending 1 Selfridge on the first MR test, less than 32M
- * composites remain undecided out of 18 quintillion 64-bit composites.  The
- * final Lucas test has no false positives.
- * Replacing the Lucas test with the F-U test won't save any time.  Replacing
- * the whole thing with the F-U test (assuming it has no false results for
- * all 64-bit values, which hasn't been verified), doesn't help either.
- * It's 2/3 the cost for primes, but much more expensive for composites.  It
- * seems of interest for > 2^64 as a different test to do in addition to BPSW.
- */
-
-
-int _XS_is_frobenius_underwood_pseudoprime(UV n)
-{
-  int bit;
-  UV x, result, multiplier, a, b, np1, len, t1, t2, na;
-  IV t;
-
-  if (n < 2) return 0;
-  if (n < 4) return 1;
-  if ((n % 2) == 0) return 0;
-  if (is_perfect_square(n,0)) return 0;
-  if (n == UV_MAX) return 0;
-
-  x = 0;
-  t = -1;
-  while ( jacobi_iu( t, n ) != -1 ) {
-    x++;
-    t = (IV)(x*x) - 4;
-  }
-  result = addmod( addmod(x, x, n), 5, n);
-  multiplier = addmod(x, 2, n);
-
-  a = 1;
-  b = 2;
-  np1 = n+1;
-  { UV v = np1; len = 1;  while (v >>= 1) len++; }
-
-  if (x == 0) {
-    for (bit = len-2; bit >= 0; bit--) {
-      t2 = addmod(b, b, n);
-      na = mulmod(a, t2, n);
-      t1 = addmod(b, a, n);
-      t2 = submod(b, a, n);
-      b = mulmod(t1, t2, n);
-      a = na;
-      if ( (np1 >> bit) & UVCONST(1) ) {
-        t1 = mulmod(a, 2, n);
-        na = addmod(t1, b, n);
-        t1 = addmod(b, b, n);
-        b = submod(t1, a, n);
-        a = na;
-      }
-    }
-  } else {
-    for (bit = len-2; bit >= 0; bit--) {
-      t1 = mulmod(a, x, n);
-      t2 = addmod(b, b, n);
-      t1 = addmod(t1, t2, n);
-      na = mulmod(a, t1, n);
-      t1 = addmod(b, a, n);
-      t2 = submod(b, a, n);
-      b = mulmod(t1, t2, n);
-      a = na;
-      if ( (np1 >> bit) & UVCONST(1) ) {
-        t1 = mulmod(a, multiplier, n);
-        na = addmod(t1, b, n);
-        t1 = addmod(b, b, n);
-        b = submod(t1, a, n);
-        a = na;
-      }
-    }
-  }
-  if (_XS_get_verbose()>1) printf("%"UVuf" is %s with x = %"UVuf"\n", n, (a == 
0 && b == result) ? "probably prime" : "composite", x);
-  if (a == 0 && b == result)
-    return 1;
-  return 0;
-}
diff --git a/factor.h b/factor.h
index c7dd3ae..2979b32 100644
--- a/factor.h
+++ b/factor.h
@@ -18,27 +18,6 @@ extern int pplus1_factor(UV n, UV *factors, UV B);
 extern int squfof_factor(UV n, UV *factors, UV rounds);
 extern int racing_squfof_factor(UV n, UV *factors, UV rounds);
 
-
-extern int _XS_is_pseudoprime(UV n, UV a);
-extern int _XS_miller_rabin(UV n, const UV *bases, int nbases);
-extern int _SPRP2(UV n);
-extern int _XS_is_prob_prime(UV n);
-extern void lucas_seq(UV* U, UV* V, UV* Qk,  UV n, IV P, IV Q, UV k);
-extern int _XS_is_lucas_pseudoprime(UV n, int strength);
-extern int _XS_is_frobenius_underwood_pseudoprime(UV n);
-extern int _XS_is_almost_extra_strong_lucas_pseudoprime(UV n, UV increment);
-
 extern UV _XS_divisor_sum(UV n);
 
-#ifdef FUNC_gcd_ui
-static UV gcd_ui(UV x, UV y) {
-  UV t;
-  if (y < x) { t = x; x = y; y = t; }
-  while (y > 0) {
-    t = y;  y = x % y;  x = t;  /* y1 <- x0 % y0 ; x1 <- y0 */
-  }
-  return x;
-}
-#endif
-
 #endif
diff --git a/lib/Math/Prime/Util/PrimeArray.pm 
b/lib/Math/Prime/Util/PrimeArray.pm
index baf7815..a47795a 100644
--- a/lib/Math/Prime/Util/PrimeArray.pm
+++ b/lib/Math/Prime/Util/PrimeArray.pm
@@ -199,8 +199,8 @@ Example:
 
 If you want sequential primes with low memory, I recommend using
 L<Math::Prime::Util/forprimes>.  It is much faster, as the tied array
-functionality in Perl is not high performance.  It does have limitations
-vs. the prime array, but many tasks find they can use it.
+functionality in Perl is not high performance.  It isn't as flexible as
+the prime array, but it is a very common pattern.
 
 If you prefer an iterator pattern, I would recommend using
 L<Math::Prime::Util/prime_iterator>.  It will be a bit faster than using this
diff --git a/primality.c b/primality.c
new file mode 100644
index 0000000..171317d
--- /dev/null
+++ b/primality.c
@@ -0,0 +1,689 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "ptypes.h"
+#include "primality.h"
+#include "mulmod.h"
+#define FUNC_gcd_ui
+#include "util.h"
+
+/* Primality related functions, including Montgomery math */
+
+/* TODO:
+ *      - Convert F-U test to Montgomery
+ *      - Convert Lucas tests to Montgomery
+ */
+
+static const UV mr_bases_const2[1] = {2};
+
+/******************************************************************************
+  Code inside USE_MONT_PRIMALITY is Montgomery math and efficient M-R from
+  Wojciech Izykowski.  See:  https://github.com/wizykowski/miller-rabin
+
+Copyright (c) 2013, Wojciech Izykowski
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * The name of the author may not be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+#if USE_MONT_PRIMALITY
+static INLINE uint64_t mont_prod64(uint64_t a, uint64_t b, uint64_t n, 
uint64_t npi)
+{
+  uint64_t t_hi, t_lo, m, mn_hi, mn_lo, u;
+  int carry;
+  /* t_hi * 2^64 + t_lo = a*b */
+  asm("mulq %3" : "=a"(t_lo), "=d"(t_hi) : "a"(a), "rm"(b));
+  m = t_lo * npi;
+  /* mn_hi * 2^64 + mn_lo = m*n */
+  asm("mulq %3" : "=a"(mn_lo), "=d"(mn_hi) : "a"(m), "rm"(n));
+  carry = t_lo + mn_lo < t_lo ? 1 : 0;
+  u = t_hi + mn_hi + carry;
+  if (u < t_hi) return u-n;
+  return u >= n ? u-n : u;
+}
+#define mont_square64(a, n, npi)  mont_prod64(a, a, n, npi)
+static INLINE UV mont_powmod64(uint64_t a, uint64_t k, uint64_t one, uint64_t 
n, uint64_t npi)
+{
+  uint64_t t = one;
+  while (k) {
+    if (k & 1) t = mont_prod64(t, a, n, npi);
+    k >>= 1;
+    if (k)     a = mont_square64(a, n, npi);
+  }
+  return t;
+}
+static INLINE uint64_t modular_inverse64(const uint64_t a)
+{
+  uint64_t u,x,w,z,q;
+
+  x = 1; z = a;
+
+  q = (-z)/z + 1;  /* = 2^64 / z                 */
+  u = - q;         /* = -q * x                   */
+  w = - q * z;     /* = b - q * z = 2^64 - q * z */
+
+  /* after first iteration all variables are 64-bit */
+
+  while (w) {
+    if (w < z) {
+      q = u; u = x; x = q; /* swap(u, x) */
+      q = w; w = z; z = q; /* swap(w, z) */
+    }
+    q = w / z;
+    u -= q * x;
+    w -= q * z;
+  }
+  return x;
+}
+static INLINE uint64_t compute_modn64(const uint64_t n)
+{
+  
+  if (n <= (1ULL << 63)) {
+    uint64_t res = ((1ULL << 63) % n) << 1;
+    return res < n ? res : res-n;
+  } else
+    return -n;
+}
+#define compute_a_times_2_64_mod_n(a, n, r)   mulmod(a, r, n)
+static INLINE uint64_t compute_2_65_mod_n(const uint64_t n, const uint64_t 
modn)
+{
+  if (n <= (1ULL << 63)) {
+    uint64_t res = modn << 1;
+    return res < n ? res : res - n;
+  } else {
+    /* n can fit 2 or 3 times in 2^65 */
+    if (n > UVCONST(12297829382473034410))
+      return -n-n;    /* 2^65 mod n = 2^65 - 2*n */
+    else
+      return -n-n-n;  /* 2^65 mod n = 2^65 - 3*n */
+  }
+}
+/* static INLINE int efficient_mr64(const uint64_t bases[], const int cnt, 
const uint64_t n) */
+static int monty_mr64(const uint64_t n, const UV* bases, int cnt)
+{
+  int i, j, t;
+  const uint64_t npi = modular_inverse64(-((int64_t)n));
+  const uint64_t r = compute_modn64(n);
+  uint64_t u = n - 1;
+  const uint64_t nr = n - r;
+
+  t = 0;
+  while (!(u&1)) {  t++;  u >>= 1;  }
+  for (j = 0; j < cnt; j++) {
+    const uint64_t a = bases[j];
+    uint64_t       A = compute_a_times_2_64_mod_n(a, n, r);
+    uint64_t       d;
+    if (a < 2)  croak("Base %"UVuf" is invalid", (UV)a);
+    if (!A) continue;  /* PRIME in subtest */
+    d = mont_powmod64(A, u, r, n, npi);  /* compute a^u mod n */
+    if (d == r || d == nr) continue;  /* PRIME in subtest */
+    for (i=1; i<t; i++) {
+      d = mont_square64(d, n, npi);
+      if (d == r) return 0;
+      if (d == nr) break;  /* PRIME in subtest */
+    }
+    if (i == t) return 0;
+  }
+  return 1;
+}
+#endif
+/******************************************************************************/
+
+
+
+
+/* Helper functions */
+static int is_perfect_square(UV n, UV* sqrtn)
+{
+  UV m;
+  m = n & 127;
+  if ((m*0x8bc40d7d) & (m*0xa1e2f5d1) & 0x14020a)  return 0;
+  m = isqrt(n);
+  if (n != (m*m))
+    return 0;
+  if (sqrtn != 0)
+    *sqrtn = m;
+  return 1;
+}
+static int jacobi_iu(IV in, UV m) {
+  int j = 1;
+  UV n = (in < 0) ? -in : in;
+
+  if (m <= 0 || (m%2) == 0) return 0;
+  if (in < 0 && (m%4) == 3) j = -j;
+  while (n != 0) {
+    while ((n % 2) == 0) {
+      n >>= 1;
+      if ( (m % 8) == 3 || (m % 8) == 5 )  j = -j;
+    }
+    { UV t = n; n = m; m = t; }
+    if ( (n % 4) == 3 && (m % 4) == 3 )  j = -j;
+    n = n % m;
+  }
+  return (m == 1) ? j : 0;
+}
+
+
+
+
+/* Fermat pseudoprime */
+int _XS_is_pseudoprime(UV const n, UV a)
+{
+  UV x;
+
+  if (n == 2 || n == 3)  return 1;
+  if (n < 5) return 0;
+  if (a < 2) croak("Base %"UVuf" is invalid", a);
+  if (a >= n) {
+    a %= n;
+    if ( a <= 1 || a == n-1 )
+      return 1;
+  }
+  x = powmod(a, n-1, n);    /* x = a^(n-1) mod n */
+  return (x == 1);
+}
+
+/* Miller-Rabin probabilistic primality test
+ * Returns 1 if probably prime relative to the bases, 0 if composite.
+ * Bases must be between 2 and n-2
+ */
+int _XS_miller_rabin(UV const n, const UV *bases, int nbases)
+{
+  UV d = n-1;
+  int b, r, s = 0;
+
+  MPUassert(n > 3, "MR called with n <= 3");
+  if ((n & 1) == 0) return 0;
+
+  if (USE_MONT_PRIMALITY && n >= UVCONST(4294967295))
+    return monty_mr64((uint64_t)n, bases, nbases);
+
+  while (!(d&1)) {  s++;  d >>= 1;  }
+
+  for (b = 0; b < nbases; b++) {
+    UV x, a = bases[b];
+    if (a < 2)  croak("Base %"UVuf" is invalid", a);
+    if (a >= n) a %= n;
+    if ( (a <= 1) || (a == n-1) )
+      continue;
+    /* n is a strong pseudoprime to base a if either:
+     *    a^d = 1 mod n
+     *    a^(d2^r) = -1 mod n for some r: 0 <= r <= s-1
+     */
+    x = powmod(a, d, n);
+    if ( (x == 1) || (x == n-1) )  continue;
+    for (r = 1; r < s; r++) {  /* r=0 was just done, test r = 1 to s-1 */
+      x = sqrmod(x, n);
+      if ( x == n-1 )  break;
+      if ( x == 1   )  return 0;
+    }
+    if (r >= s)  return 0;
+  }
+  return 1;
+}
+
+int _XS_BPSW(UV const n)
+{
+  if (n == 2 || n == 3 || n == 5) return 1;
+  if (n < 7 || (n%2) == 0 || n == UV_MAX) return 0;
+
+#if !USE_MONT_PRIMALITY
+  return    _XS_miller_rabin(n, mr_bases_const2, 1)
+         && _XS_is_almost_extra_strong_lucas_pseudoprime(n,1);
+#else
+  if (n < UVCONST(4294967295)) {
+    return    _XS_miller_rabin(n, mr_bases_const2, 1)
+           && _XS_is_almost_extra_strong_lucas_pseudoprime(n,1);
+  } else {
+    const uint64_t npi = modular_inverse64(-((int64_t)n));
+    const uint64_t montr = compute_modn64(n);
+    const uint64_t mont2 = compute_2_65_mod_n(n, montr);
+    uint64_t u = n-1;
+    const uint64_t nr = n-montr;
+    int i, t = 0;
+    UV P, V, d, s;
+
+    /* M-R with base 2 */
+    while (!(u&1)) {  t++;  u >>= 1;  }
+    {
+      uint64_t A = mont2;
+      if (A) {
+        uint64_t d = mont_powmod64(A, u, montr, n, npi);
+        if (d != montr && d != nr) {
+          for (i=1; i<t; i++) {
+            d = mont_square64(d, n, npi);
+            if (d == montr) return 0;
+            if (d == nr) break;
+          }
+          if (i == t)
+            return 0;
+        }
+      }
+    }
+    /* AES Lucas test */
+    P = 3;
+    while (1) {
+      UV D = P*P - 4;
+      d = gcd_ui(D, n);
+      if (d > 1 && d < n)
+        return 0;
+      if (jacobi_iu(D, n) == -1)
+        break;
+      if (P == (3+20) && is_perfect_square(n, 0)) return 0;
+      P++;
+      if (P > 65535)
+        croak("lucas_extrastrong_params: P exceeded 65535");
+    }
+
+    d = n+1;
+    s = 0;
+    while ( (d & 1) == 0 ) {  s++;  d >>= 1; }
+
+    {
+      const uint64_t montP = compute_a_times_2_64_mod_n(P, n, montr);
+      UV W, b;
+      W = submod(  mont_prod64( montP, montP, n, npi),  mont2, n);
+      V = montP;
+      { UV v = d; b = 1; while (v >>= 1) b++; }
+      while (b-- > 1) {
+        if ( (d >> (b-1)) & UVCONST(1) ) {
+          V = submod(  mont_prod64(V, W, n, npi),  montP, n);
+          W = submod(  mont_prod64(W, W, n, npi),  mont2, n);
+        } else {
+          W = submod(  mont_prod64(V, W, n, npi),  montP, n);
+          V = submod(  mont_prod64(V, V, n, npi),  mont2, n);
+        }
+      }
+    }
+
+    if (V == mont2 || V == (n-mont2))
+      return 1;
+    while (s-- > 1) {
+      if (V == 0)
+        return 1;
+      V = submod(  mont_prod64(V, V, n, npi),  mont2, n);
+      if (V == mont2)
+        return 0;
+    }
+  }
+  return 0;
+#endif
+}
+
+/* Generic Lucas sequence for any appropriate P and Q */
+void lucas_seq(UV* Uret, UV* Vret, UV* Qkret, UV n, IV P, IV Q, UV k)
+{
+  UV U, V, b, Dmod, Qmod, Pmod, Qk;
+
+  if (k == 0) {
+    *Uret = 0;
+    *Vret = 2;
+    *Qkret = Q;
+    return;
+  }
+
+  Qmod = (Q < 0)  ?  (UV)(Q + (IV)n)  :  (UV)Q;
+  Pmod = (P < 0)  ?  (UV)(P + (IV)n)  :  (UV)P;
+  Dmod = submod( mulmod(Pmod, Pmod, n), mulmod(4, Qmod, n), n);
+  MPUassert(Dmod != 0, "lucas_seq: D is 0");
+  U = 1;
+  V = Pmod;
+  Qk = Qmod;
+  { UV v = k; b = 1; while (v >>= 1) b++; }
+
+  if (Q == 1) {
+    while (b > 1) {
+      U = mulmod(U, V, n);
+      V = mulsubmod(V, V, 2, n);
+      b--;
+      if ( (k >> (b-1)) & UVCONST(1) ) {
+        UV t2 = mulmod(U, Dmod, n);
+        U = muladdmod(U, Pmod, V, n);
+        if (U & 1) { U = (n>>1) + (U>>1) + 1; } else { U >>= 1; }
+        V = muladdmod(V, P, t2, n);
+        if (V & 1) { V = (n>>1) + (V>>1) + 1; } else { V >>= 1; }
+      }
+    }
+  } else if (P == 1 && Q == -1) {
+    /* This is about 30% faster than the generic code below.  Since 50% of
+     * Lucas and strong Lucas tests come here, I think it's worth doing. */
+    int sign = Q;
+    while (b > 1) {
+      U = mulmod(U, V, n);
+      if (sign == 1) V = mulsubmod(V, V, 2, n);
+      else           V = muladdmod(V, V, 2, n);
+      sign = 1;   /* Qk *= Qk */
+      b--;
+      if ( (k >> (b-1)) & UVCONST(1) ) {
+        UV t2 = mulmod(U, Dmod, n);
+        U = addmod(U, V, n);
+        if (U & 1) { U = (n>>1) + (U>>1) + 1; } else { U >>= 1; }
+        V = addmod(V, t2, n);
+        if (V & 1) { V = (n>>1) + (V>>1) + 1; } else { V >>= 1; }
+        sign = -1;  /* Qk *= Q */
+      }
+    }
+    if (sign == 1) Qk = 1;
+  } else {
+    while (b > 1) {
+      U = mulmod(U, V, n);
+      V = mulsubmod(V, V, addmod(Qk,Qk,n), n);
+      Qk = sqrmod(Qk, n);
+      b--;
+      if ( (k >> (b-1)) & UVCONST(1) ) {
+        UV t2 = mulmod(U, Dmod, n);
+        U = muladdmod(U, Pmod, V, n);
+        if (U & 1) { U = (n>>1) + (U>>1) + 1; } else { U >>= 1; }
+        V = muladdmod(V, P, t2, n);
+        if (V & 1) { V = (n>>1) + (V>>1) + 1; } else { V >>= 1; }
+        Qk = mulmod(Qk, Qmod, n);
+      }
+    }
+  }
+  *Uret = U;
+  *Vret = V;
+  *Qkret = Qk;
+}
+
+/* Lucas tests:
+ *  0: Standard
+ *  1: Strong
+ *  2: Extra Strong (Mo/Jones/Grantham)
+ *
+ * None of them have any false positives for the BPSW test.  Also see the
+ * "almost extra strong" test.
+ */
+int _XS_is_lucas_pseudoprime(UV n, int strength)
+{
+  IV P, Q, D;
+  UV U, V, Qk, d, s;
+
+  if (n == 2 || n == 3) return 1;
+  if (n < 5 || (n%2) == 0) return 0;
+  if (n == UV_MAX) return 0;
+
+  if (strength < 2) {
+    UV Du = 5;
+    IV sign = 1;
+    while (1) {
+      D = Du * sign;
+      if (gcd_ui(Du, n) > 1 && gcd_ui(Du, n) != n) return 0;
+      if (jacobi_iu(D, n) == -1)
+        break;
+      if (Du == 21 && is_perfect_square(n, 0)) return 0;
+      Du += 2;
+      sign = -sign;
+    }
+    P = 1;
+    Q = (1 - D) / 4;
+  } else {
+    P = 3;
+    Q = 1;
+    while (1) {
+      D = P*P - 4;
+      if (gcd_ui(D, n) > 1 && gcd_ui(D, n) != n) return 0;
+      if (jacobi_iu(D, n) == -1)
+        break;
+      if (P == 21 && is_perfect_square(n, 0)) return 0;
+      P++;
+    }
+  }
+  MPUassert( D == (P*P - 4*Q) , "is_lucas_pseudoprime: incorrect DPQ");
+
+  d = n+1;
+  s = 0;
+  if (strength > 0)
+    while ( (d & 1) == 0 ) {  s++;  d >>= 1; }
+  lucas_seq(&U, &V, &Qk, n, P, Q, d);
+
+  if (strength == 0) {
+    if (U == 0)
+      return 1;
+  } else if (strength == 1) {
+    if (U == 0)
+      return 1;
+    /* Now check to see if V_{d*2^r} == 0 for any 0 <= r < s */
+    while (s--) {
+      if (V == 0)
+        return 1;
+      if (s) {
+        V = mulsubmod(V, V, addmod(Qk,Qk,n), n);
+        Qk = sqrmod(Qk, n);
+      }
+    }
+  } else {
+    if ( U == 0 && (V == 2 || V == (n-2)) )
+      return 1;
+    /* Now check to see if V_{d*2^r} == 0 for any 0 <= r < s-1 */
+    s--;
+    while (s--) {
+      if (V == 0)
+        return 1;
+      if (s)
+        V = mulsubmod(V, V, 2, n);
+    }
+  }
+  return 0;
+}
+
+/* A generalization of Pari's shortcut to the extra-strong Lucas test.
+ * I've added a gcd check at the top, which needs to be done and also results
+ * in fewer pseudoprimes.  Pari always does trial division to 100 first so
+ * is unlikely to come up there.  This only calculate V, which can be done
+ * faster, but that means we have more pseudoprimes than the standard
+ * extra-strong test.
+ *
+ * increment:  1 for Baillie OEIS, 2 for Pari.
+ *
+ * With increment = 1, these results will be a subset of the extra-strong
+ * Lucas pseudoprimes.  With increment = 2, we produce Pari's results.
+ */
+int _XS_is_almost_extra_strong_lucas_pseudoprime(UV n, UV increment)
+{
+  UV P, V, d, s;
+
+  if (n == 2 || n == 3 || n == 5) return 1;
+  if (n < 7 || (n%2) == 0) return 0;
+  if (n == UV_MAX) return 0;
+  if (increment < 1 || increment > 256)
+    croak("Invalid lucas paramater increment: %"UVuf"\n", increment);
+
+  P = 3;
+  while (1) {
+    UV D = P*P - 4;
+    d = gcd_ui(D, n);
+    if (d > 1 && d < n)
+      return 0;
+    if (jacobi_iu(D, n) == -1)
+      break;
+    if (P == (3+20*increment) && is_perfect_square(n, 0)) return 0;
+    P += increment;
+    if (P > 65535)
+      croak("lucas_extrastrong_params: P exceeded 65535");
+  }
+  if (P >= n)  P %= n;   /* Never happens with increment < 4 */
+
+  d = n+1;
+  s = 0;
+  while ( (d & 1) == 0 ) {  s++;  d >>= 1; }
+
+  {
+    UV W, b;
+    V = P;
+    W = mulsubmod(P, P, 2, n);
+    { UV v = d; b = 1; while (v >>= 1) b++; }
+    while (b-- > 1) {
+      if ( (d >> (b-1)) & UVCONST(1) ) {
+        V = mulsubmod(V, W, P, n);
+        W = mulsubmod(W, W, 2, n);
+      } else {
+        W = mulsubmod(V, W, P, n);
+        V = mulsubmod(V, V, 2, n);
+      }
+    }
+  }
+  if (V == 2 || V == (n-2))
+    return 1;
+  while (s-- > 1) {
+    if (V == 0)
+      return 1;
+    V = mulsubmod(V, V, 2, n);
+    if (V == 2)
+      return 0;
+  }
+  return 0;
+}
+
+/*
+ * The Frobenius-Underwood test has no known counterexamples below 10^13, but
+ * has not been extensively tested above that.  This is the Minimal Lambda+2
+ * test from section 9 of "Quadratic Composite Tests" by Paul Underwood.
+ *
+ * It is generally slower than the AES Lucas test, but for large values will
+ * be faster than a BPSW test.  Currently it is of use mainly for numbers
+ * larger than 2^64 as an additional non-correlated test.
+ *
+ * TODO: Convert to Montgomery
+ */
+int _XS_is_frobenius_underwood_pseudoprime(UV n)
+{
+  int bit;
+  UV x, result, multiplier, a, b, np1, len, t1, t2, na;
+  IV t;
+
+  if (n < 2) return 0;
+  if (n < 4) return 1;
+  if ((n % 2) == 0) return 0;
+  if (is_perfect_square(n,0)) return 0;
+  if (n == UV_MAX) return 0;
+
+  x = 0;
+  t = -1;
+  while ( jacobi_iu( t, n ) != -1 ) {
+    x++;
+    t = (IV)(x*x) - 4;
+  }
+  result = addmod( addmod(x, x, n), 5, n);
+  multiplier = addmod(x, 2, n);
+
+  a = 1;
+  b = 2;
+  np1 = n+1;
+  { UV v = np1; len = 1;  while (v >>= 1) len++; }
+
+  if (x == 0) {
+    for (bit = len-2; bit >= 0; bit--) {
+      t2 = addmod(b, b, n);
+      na = mulmod(a, t2, n);
+      t1 = addmod(b, a, n);
+      t2 = submod(b, a, n);
+      b = mulmod(t1, t2, n);
+      a = na;
+      if ( (np1 >> bit) & UVCONST(1) ) {
+        t1 = mulmod(a, 2, n);
+        na = addmod(t1, b, n);
+        t1 = addmod(b, b, n);
+        b = submod(t1, a, n);
+        a = na;
+      }
+    }
+  } else {
+    for (bit = len-2; bit >= 0; bit--) {
+      t1 = mulmod(a, x, n);
+      t2 = addmod(b, b, n);
+      t1 = addmod(t1, t2, n);
+      na = mulmod(a, t1, n);
+      t1 = addmod(b, a, n);
+      t2 = submod(b, a, n);
+      b = mulmod(t1, t2, n);
+      a = na;
+      if ( (np1 >> bit) & UVCONST(1) ) {
+        t1 = mulmod(a, multiplier, n);
+        na = addmod(t1, b, n);
+        t1 = addmod(b, b, n);
+        b = submod(t1, a, n);
+        a = na;
+      }
+    }
+  }
+  if (_XS_get_verbose()>1) printf("%"UVuf" is %s with x = %"UVuf"\n", n, (a == 
0 && b == result) ? "probably prime" : "composite", x);
+  if (a == 0 && b == result)
+    return 1;
+  return 0;
+}
+
+
+/******************************************************************************/
+
+
+/* Select M-R bases from http://miller-rabin.appspot.com/, 26 July 2013 */
+#if BITS_PER_WORD == 32
+static const UV mr_bases_small_2[2] = {31, 73};
+static const UV mr_bases_small_3[3] = {2, 7, 61};
+#else
+static const UV mr_bases_large_1[1] = { UVCONST(  9345883071009581737 ) };
+static const UV mr_bases_large_2[2] = { UVCONST(         336781006125 ),
+                                        UVCONST(     9639812373923155 ) };
+static const UV mr_bases_large_3[3] = { UVCONST(  4230279247111683200 ),
+                                        UVCONST( 14694767155120705706 ),
+                                        UVCONST( 16641139526367750375 ) };
+static const UV mr_bases_large_7[7] = { 2, 325, 9375, 28178, 450775, 9780504, 
1795265022 };
+#endif
+
+int _XS_is_prob_prime(UV n)
+{
+  int ret;
+
+  if (n < 11) {
+    if (n == 2 || n == 3 || n == 5 || n == 7)     return 2;
+    else                                          return 0;
+  }
+  if (!(n%2) || !(n%3) || !(n%5) || !(n%7))       return 0;
+  if (n <  121) /* 11*11 */                       return 2;
+  if (!(n%11) || !(n%13) || !(n%17) || !(n%19) ||
+      !(n%23) || !(n%29) || !(n%31) || !(n%37) ||
+      !(n%41) || !(n%43) || !(n%47) || !(n%53))   return 0;
+  if (n < 3481) /* 59*59 */                       return 2;
+
+#if BITS_PER_WORD == 32
+  /* We could use one base when n < 49191, two when n < 360018361. */
+  if (n < UVCONST(9080191))
+    ret = _XS_miller_rabin(n, mr_bases_small_2, 2);
+  else
+    ret = _XS_miller_rabin(n, mr_bases_small_3, 3);
+#else
+  /* AESLSP test costs about 1.5 Selfridges, vs. ~2.2 for strong Lucas.
+   * So it works out to be faster to do AES-BPSW vs. 3 M-R tests. */
+  if (n < UVCONST(341531))
+    ret = _XS_miller_rabin(n, mr_bases_large_1, 1);
+  else if (n < UVCONST(1050535501))
+    ret = _XS_miller_rabin(n, mr_bases_large_2, 2);
+  else
+    ret = _XS_BPSW(n);
+  /*
+    ret = efficient_mr64(mr_bases_large_7, 7, n);
+    ret = _XS_miller_rabin(n, mr_bases_large_7, 7);
+  */
+#endif
+  return 2*ret;
+}
diff --git a/primality.h b/primality.h
new file mode 100644
index 0000000..ec7e0f9
--- /dev/null
+++ b/primality.h
@@ -0,0 +1,22 @@
+#ifndef MPU_PRIMALITY_H
+#define MPU_PRIMALITY_H
+
+#include "ptypes.h"
+
+#if BITS_PER_WORD == 64 && HAVE_STD_U64 && defined(__GNUC__) && 
defined(__x86_64__)
+#define USE_MONT_PRIMALITY 1
+#else
+#define USE_MONT_PRIMALITY 0
+#endif
+
+extern int _XS_is_pseudoprime(UV const n, UV a);
+extern int _XS_miller_rabin(UV const n, const UV *bases, int nbases);
+extern void lucas_seq(UV* U, UV* V, UV* Qk,  UV n, IV P, IV Q, UV k);
+extern int _XS_is_lucas_pseudoprime(UV n, int strength);
+extern int _XS_is_frobenius_underwood_pseudoprime(UV n);
+extern int _XS_is_almost_extra_strong_lucas_pseudoprime(UV n, UV increment);
+
+extern int _XS_BPSW(UV const n);
+extern int _XS_is_prob_prime(UV n);
+
+#endif
diff --git a/util.c b/util.c
index 523ce65..b4436af 100644
--- a/util.c
+++ b/util.c
@@ -58,7 +58,7 @@
 #include "ptypes.h"
 #include "util.h"
 #include "sieve.h"
-#include "factor.h"
+#include "primality.h"
 #include "cache.h"
 #include "lehmer.h"
 
diff --git a/util.h b/util.h
index 4194879..efc4107 100644
--- a/util.h
+++ b/util.h
@@ -47,4 +47,15 @@ static UV isqrt(UV n) {
   return root;
 }
 
+#ifdef FUNC_gcd_ui
+static UV gcd_ui(UV x, UV y) {
+  UV t;
+  if (y < x) { t = x; x = y; y = t; }
+  while (y > 0) {
+    t = y;  y = x % y;  x = t;  /* y1 <- x0 % y0 ; x1 <- y0 */
+  }
+  return x;
+}
+#endif
+
 #endif
diff --git a/xt/primality-small.pl b/xt/primality-small.pl
index 70d5900..98491f4 100755
--- a/xt/primality-small.pl
+++ b/xt/primality-small.pl
@@ -5,7 +5,7 @@ $| = 1;  # fast pipes
 
 # Make sure the is_prob_prime functionality is working for small inputs.
 # Good for making sure the first few M-R bases are set up correctly.
-my $limit = 1_000_000_000;
+my $limit = shift || 1_000_000_000;
 
 use Math::Prime::Util qw/is_prob_prime/;
 # Use another code base for comparison.

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