[libmath-prime-util-perl] 06/16: Add perfect square discriminator

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


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

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

commit 8f4796dfbec39a962b0ae093007b3ce097930e36
Author: Dana Jacobsen <dana at acm.org>
Date:   Fri Jun 8 23:05:11 2012 -0600

    Add perfect square discriminator
---
 factor.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 49 insertions(+), 9 deletions(-)

diff --git a/factor.c b/factor.c
index dcfec63..656389a 100644
--- a/factor.c
+++ b/factor.c
@@ -178,6 +178,54 @@ int trial_factor(UV n, UV *factors, UV maxtrial)
 /* n^2 + a mod m */
 #define sqraddmod(n, a, m)     addmod(sqrmod(n,m),  a,m)
 
+/* Return 0 if n is not a perfect square.  Set sqrtn to int(sqrt(n)) if so.
+ *
+ * A simplistic solution (but not unhelpful) is:
+ *
+ *     return ( ((m&2)!= 0) || ((m&7)==5) || ((m&11) == 8) )  ?  0  :  1;
+ *
+ * The following Bloom filter cascade works very well indeed.  Read all
+ * about it here: http://mersenneforum.org/showpost.php?p=110896
+ */
+static int is_perfect_square(UV n, UV* sqrtn)
+{
+  UV m, lm;
+  m = n & 127;
+  if ((m*0x8bc40d7d) & (m*0xa1e2f5d1) & 0x14020a)  return 0;
+  /* 82% of non-squares rejected here */
+
+#if 0
+  /* The big deal with this technique is that you do two total operations,
+   * one cheap (the & 127 above), one expensive (the modulo below) on n.
+   * The rest of the operations are 32-bit operations.  This is a huge win
+   * if n is multiprecision.
+   * However, in this file we're doing native precision sqrt, so it just
+   * isn't expensive enough to justify this second filter set.
+   */
+  lm = n % UVCONST(63*25*11*17*19*23*31);
+  m = lm % 63;
+  if ((m*0x3d491df7) & (m*0xc824a9f9) & 0x10f14008) return 0;
+  m = lm % 25;
+  if ((m*0x1929fc1b) & (m*0x4c9ea3b2) & 0x51001005) return 0;
+  m = 0xd10d829a*(lm%31);
+  if (m & (m+0x672a5354) & 0x21025115) return 0;
+  m = lm % 23;
+  if ((m*0x7bd28629) & (m*0xe7180889) & 0xf8300) return 0;
+  m = lm % 19;
+  if ((m*0x1b8bead3) & (m*0x4d75a124) & 0x4280082b) return 0;
+  m = lm % 17;
+  if ((m*0x6736f323) & (m*0x9b1d499) & 0xc0000300) return 0;
+  m = lm % 11;
+  if ((m*0xabf1a3a7) & (m*0x2612bf93) & 0x45854000) return 0;
+  /* 99.92% of non-squares are rejected now */
+#endif
+  m = sqrt(n);
+  if (n != (m*m))
+    return 0;
+
+  if (sqrtn != 0) *sqrtn = m;
+  return 1;
+}
 
 /* Miller-Rabin probabilistic primality test
  * Returns 1 if probably prime relative to the bases, 0 if composite.
@@ -360,15 +408,7 @@ int holf_factor(UV n, UV *factors, UV rounds)
     s = sqrt(n*i);                      /* TODO: overflow here */
     if ( (s*s) != (n*i) )  s++;
     m = sqrmod(s, n);
-    /* Cheaper would be:
-     *     if (m is probably not a perfect sequare)  continue;
-     *     f = sqrt(m);
-     *     if (f*f == m) { yay }
-     */
-    if ( ((m&2)!= 0) || ((m&7)==5) || ((m&11) == 8) )
-      continue;
-    f = sqrt(m);                        /* expensive */
-    if ( (f*f) == m ) {
+    if (is_perfect_square(m, &f)) {
       f = gcd_ui( (s>f) ? s-f : f-s, n);
       /* This should always succeed, but with overflow concerns.... */
       if ((f == 1) || (f == n))

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