changeset 31402:0783418ac443

factor.m: Guard against non-prime factors returned from C++. factor.m: Extensive testing reveals a small chance that __pollardrho__ can return a composite number as a factor for some inputs. Call isprime to trap that case. Add BISTs.
author Arun Giridhar <arungiridhar@gmail.com>
date Sun, 06 Nov 2022 11:40:07 -0500
parents e7fc6251b698
children 821cdacfdca7
files scripts/specfun/factor.m
diffstat 1 files changed, 29 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/specfun/factor.m	Sat Nov 05 19:15:13 2022 +0100
+++ b/scripts/specfun/factor.m	Sun Nov 06 11:40:07 2022 -0500
@@ -95,18 +95,27 @@
   sortflag = false;
   if (isprime (q))
     pf(end+1) = q;
-  else
+  elseif (q > 1)
     ## Use Pollard Rho technique to pull factors one at a time.
     while (q > 1e10 && ! isprime (q))
-      pr = feval (cls, __pollardrho__ (q));  # pr is a prime factor.
+      pr = feval (cls, __pollardrho__ (q));  # pr is a factor of q.
+
+      ## There is a small chance (13 in 1e5) that pr is not actually prime.
+      ## To guard against that, factorize pr, which will force smaller factors
+      ## to be found.  The use of isprime above guards against infinite
+      ## recursion.
+      if (! isprime (pr))
+        pr = factor (pr);
+      end
+
       [pf, q] = reducefactors (q, pf, pr);
-      ## q is now divided by all occurrences of factor pr.
+      ## q is now divided by all occurrences of factor(s) pr.
       sortflag = true;
     endwhile
 
     if (isprime (q))
       pf(end+1) = q;
-    else
+    elseif (q > 1)
       ## If we are here, then q is composite but less than 1e10,
       ## and that is fast enough to test by division.
       largeprimes = primes (feval (cls, sqrt (q)));
@@ -167,6 +176,22 @@
 %!   assert (all ([0,pf] != [pf,0]));
 %! endfor
 
+## Make sure that all factors returned are indeed prime, even when
+## __pollardrho__ returns a composite factor.
+%!assert (all (isprime (factor (uint64 (18446744073707633197)))))
+%!assert (all (isprime (factor (uint64 (18446744073707551733)))))
+%!assert (all (isprime (factor (uint64 (18446744073709427857)))))
+%!assert (all (isprime (factor (uint64 (18446744073709396891)))))
+%!assert (all (isprime (factor (uint64 (18446744073708666563)))))
+%!assert (all (isprime (factor (uint64 (18446744073708532009)))))
+%!assert (all (isprime (factor (uint64 (18446744073708054211)))))
+%!assert (all (isprime (factor (uint64 (18446744073707834741)))))
+%!assert (all (isprime (factor (uint64 (18446744073707298053)))))
+%!assert (all (isprime (factor (uint64 (18446744073709407383)))))
+%!assert (all (isprime (factor (uint64 (18446744073708730121)))))
+%!assert (all (isprime (factor (uint64 (18446744073708104447)))))
+%!assert (all (isprime (factor (uint64 (18446744073709011493)))))
+
 %!assert (factor (uint8 (8)), uint8 ([2 2 2]))
 %!assert (factor (single (8)), single ([2 2 2]))
 %!test