Hi,
factor in coreutils accepts 64 bit numbers, but can be very slow, e.g.,
try
factor 18446743979220271189
Attached is a patch to use the the Pollard rho factorisation algorithm.
On my ancient dog slow PC it does the above factorisation in about 1/4
seconds instead of 2 minutes.
It factors a number n in time approx O(n**(1/4)) so should be perfectly
OK on any 64 bit number. [If anyone has a 128 bit machine handy feel
free to let me play :-)].
Ralph.
--- orig/coreutils-6.9/src/factor.c 2007-03-19 09:36:43.000000000 +1200
+++ coreutils-6.9/src/factor.c 2007-05-16 20:29:28.000000000 +1200
@@ -16,7 +16,8 @@
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Paul Rubin <[EMAIL PROTECTED]>.
- Adapted for GNU, fixed to factor UINT_MAX by Jim Meyering. */
+ Adapted for GNU, fixed to factor UINT_MAX by Jim Meyering,
+ Changed to use the Pollard rho algorithm by Ralph Loader. */
#include <config.h>
#include <getopt.h>
@@ -42,24 +43,6 @@
/* Token delimiters when reading from a file. */
#define DELIM "\n\t "
-/* The maximum number of factors, including -1, for negative numbers. */
-#define MAX_N_FACTORS (sizeof (uintmax_t) * CHAR_BIT)
-
-/* The trial divisor increment wheel. Use it to skip over divisors that
- are composites of 2, 3, 5, 7, or 11. The part from WHEEL_START up to
- WHEEL_END is reused periodically, while the "lead in" is used to test
- for those primes and to jump onto the wheel. For more information, see
- http://www.utm.edu/research/primes/glossary/WheelFactorization.html */
-
-#include "wheel-size.h" /* For the definition of WHEEL_SIZE. */
-static const unsigned char wheel_tab[] =
- {
-#include "wheel.h"
- };
-
-#define WHEEL_START (wheel_tab + WHEEL_SIZE)
-#define WHEEL_END (wheel_tab + (sizeof wheel_tab / sizeof wheel_tab[0]))
-
/* The name this program was run with. */
char *program_name;
@@ -92,50 +75,341 @@
exit (status);
}
-/* FIXME: comment */
-static size_t
-factor (uintmax_t n0, size_t max_n_factors, uintmax_t *factors)
+/* Pollard-rho based factoring for 64 bit numbers. */
+
+/* First 64 primes. Should be enough to ensure no false negatives whatsoever on
+ * the Fermat primality test, for 64 bit uintmax_t. */
+#define NPRIMES 64
+const unsigned primes[NPRIMES] = {
+ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
+ 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
+ 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197,
+ 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
+ 283, 293, 307, 311
+};
+
+
+/* Number of bits in uintmax_t. */
+#define UINTMAX_BITS (sizeof (uintmax_t) * CHAR_BIT)
+
+/* The uintmax_t value with just the top bit set. */
+#define TOP_BIT (((uintmax_t) 1) << (UINTMAX_BITS - 1))
+
+/* Maximum number of factors of a uintmax_t value. Bounded by number of
+ * bits. */
+#define MAX_N_FACTORS UINTMAX_BITS
+
+/* Just above sqrt of the maximum uintmax_t value. Below this value, we may
+ * multiply without worrying about overflow. */
+#define MAX_HALF_INTMAX (((uintmax_t) 1) << (UINTMAX_BITS / 2))
+
+
+#if __GNUC__ >= 4
+/* Recent versions of GCC have this as a builtin. */
+#define countlz __builtin_clzll
+#else
+/* Return number of leading zero bits, assumes x is not zero. */
+static unsigned countlz (uintmax_t x)
+{
+ unsigned result = UINTMAX_BITS - 1;
+ assert (UINTMAX_BITS <= 128);
+ /* Anyone want to lend me a 128 bit machine? */
+ if (UINTMAX_BITS > 64 && (x >> 64) != 0) {
+ /* The % UINTMAX_BITS is to avoid compiler warnings on <= 64 bits. */
+ x >>= 64 % UINTMAX_BITS;
+ result -= 64;
+ }
+ if (UINTMAX_BITS > 32 && (x >> 32) != 0) {
+ /* The % UINTMAX_BITS is to avoid compiler warnings on <= 32 bits. */
+ x >>= 32 % UINTMAX_BITS;
+ result -= 32;
+ }
+ if (x >> 16 != 0) {
+ x >>= 16;
+ result -= 16;
+ }
+ if (x >> 8 != 0) {
+ x >>= 8;
+ result -= 8;
+ }
+ if (x >> 4 != 0) {
+ x >>= 4;
+ result -= 4;
+ }
+ if (x >> 2 != 0) {
+ x >>= 2;
+ result -= 2;
+ }
+ if (x >> 1 != 0) {
+ x >>= 1;
+ result -= 1;
+ }
+ return result;
+}
+#endif
+
+
+/* Modular addition. */
+uintmax_t add (uintmax_t x, uintmax_t y, uintmax_t modulus)
{
- uintmax_t n = n0, d, q;
- size_t n_factors = 0;
- unsigned char const *w = wheel_tab;
-
- if (n <= 1)
- return n_factors;
-
- /* The exit condition in the following loop is correct because
- any time it is tested one of these 3 conditions holds:
- (1) d divides n
- (2) n is prime
- (3) n is composite but has no factors less than d.
- If (1) or (2) obviously the right thing happens.
- If (3), then since n is composite it is >= d^2. */
+ uintmax_t result = x + y;
+ if (result < x || result >= modulus)
+ result -= modulus;
+ return result;
+}
- d = 2;
- do
- {
- q = n / d;
- while (n == q * d)
- {
- assert (n_factors < max_n_factors);
- factors[n_factors++] = d;
- n = q;
- q = n / d;
- }
- d += *(w++);
- if (w == WHEEL_END)
- w = WHEEL_START;
+
+/* Modular multiplication. */
+uintmax_t mult (uintmax_t x, uintmax_t y, uintmax_t modulus)
+{
+ unsigned lz;
+ unsigned i;
+ uintmax_t result;
+
+ /* If both x and y fit in the bottom half of an uintmax_t, then we can
+ * use '*' without fear of overflow. */
+ if (x < MAX_HALF_INTMAX && y < MAX_HALF_INTMAX)
+ return x * y % modulus;
+
+ if (x == 0)
+ return 0;
+
+ /* Otherwise we do things bit by bit to avoid overflow. */
+ lz = countlz (x);
+ x <<= lz;
+ result = y;
+
+ for (i = lz + 1; i != UINTMAX_BITS; ++i) {
+ result = add (result, result, modulus);
+ x += x;
+ if (x & TOP_BIT)
+ result = add (result, y, modulus);
}
- while (d <= q);
+ return result;
+}
- if (n != 1 || n0 == 1)
- {
- assert (n_factors < max_n_factors);
- factors[n_factors++] = n;
+
+/* Modular exponentiation. */
+uintmax_t power (uintmax_t base, uintmax_t exp, uintmax_t modulus)
+{
+ unsigned lz;
+ unsigned i;
+ uintmax_t result;
+
+ if (exp == 0)
+ return 1;
+
+ lz = countlz (exp);
+ exp <<= lz;
+
+ result = base;
+ for (i = lz + 1; i != UINTMAX_BITS; ++i) {
+ result = mult (result, result, modulus);
+ exp += exp;
+ if (exp & TOP_BIT)
+ result = mult (base, result, modulus);
+ }
+ return result;
+}
+
+
+/* Non modular exponentiation. */
+uintmax_t small_power (uintmax_t base, uintmax_t exp)
+{
+ unsigned lz;
+ unsigned i;
+ uintmax_t result;
+
+ if (exp == 0)
+ return 1;
+
+ lz = countlz (exp);
+ exp <<= lz;
+
+ result = base;
+ for (i = lz + 1; i != UINTMAX_BITS; ++i) {
+ result *= result;
+ exp += exp;
+ if (exp & TOP_BIT)
+ result *= base;
+ }
+ return result;
+}
+
+
+/* factors should be an array big enough to hold the factors; MAX_N_FACTORS will
+ * do. Returns pointer to just-past the last factor. */
+static uintmax_t * raw_factorise (uintmax_t n, uintmax_t * factors);
+
+static int uintmax_compare (const void * aa, const void * bb)
+{
+ const uintmax_t * a = aa;
+ const uintmax_t * b = bb;
+ if (*a < *b)
+ return -1;
+ else if (*a > *b)
+ return 1;
+ else
+ return 0;
+}
+
+
+/* Factorises into primes, and sorts the results. */
+static size_t factorise (uintmax_t n, uintmax_t * factors)
+{
+ uintmax_t * end = factors;
+ unsigned count;
+
+ /* First deal to factors of 2, 3, 5. Not strictly necessary, but gets some
+ * common cases out the the way quickly. This means that the smallest
+ * number that requires Pollard rho factorisation is 49. */
+ while ((n % 2) == 0) {
+ n /= 2;
+ *end++ = 2;
+ }
+ while ((n % 3) == 0) {
+ n /= 3;
+ *end++ = 3;
+ }
+ while ((n % 5) == 0) {
+ n /= 5;
+ *end++ = 5;
+ }
+
+ end = raw_factorise (n, end);
+ count = end - factors;
+
+ qsort (factors, count, sizeof (uintmax_t), uintmax_compare);
+ return count;
+}
+
+
+/* Fills in an array with each item (n/p) where p is a prime factor of n,
+ * removing duplicates. */
+static size_t calc_cofactors (uintmax_t n, uintmax_t * cofactors)
+{
+ uintmax_t factors[MAX_N_FACTORS];
+ size_t nfactors = factorise (n, factors);
+ uintmax_t last = 0;
+ unsigned count = 0;
+ unsigned i;
+ for (i = 0; i != nfactors; ++i) {
+ if (factors[i] != last) {
+ last = factors[i];
+ cofactors[count++] = n / factors[i];
+ }
+ }
+ return count;
+}
+
+
+/* Test for primeness, using Fermats little theorem. This is a probablistic
+ * test, but the chance of a given prime number not being detected is about
+ * (1/2)**NPRIMES. When UINTMAX_BITS==64, there are probably no uintmax_t
+ * values for which the test fails. */
+static bool is_prime (uintmax_t n)
+{
+ uintmax_t cofactors[MAX_N_FACTORS];
+ unsigned needed;
+ unsigned num_cofactors;
+ unsigned i;
+
+ /* First, quick check of 2. Catches most composites. */
+ if (power (2, n - 1, n) != 1)
+ return false;
+
+ num_cofactors = calc_cofactors (n - 1, cofactors);
+
+ /* Check that we have enough bits in needed. We need one bit for each
+ * distinct prime factor of n-1. The test is a bit loose but is a constant
+ * expression. */
+ assert (sizeof (needed) * 4 >= sizeof (uintmax_t) &&
+ UINTMAX_BITS >= 64);
+ /* We want to see something of order (a multiple of) (n-1)/p for each
+ * prime factor of n-1. Keep a bit mask of what is outstanding. */
+ needed = (1 << num_cofactors) - 1;
+
+ for (i = 0; i != NPRIMES; ++i) {
+ /* Note that it is not essential to use primes for this test... but if
+ * the test power(x,y,n)!=1 is true, then it is also true replacing x
+ * with some prime factor of x. So we may as well just do primes. */
+ unsigned prime = primes[i];
+ unsigned j;
+ if (prime != 2 && power (prime, n - 1, n) != 1)
+ return false;
+ for (j = 0; j != num_cofactors; ++j) {
+ if ((needed & (1 << j)) && power (prime, cofactors[j], n) != 1) {
+ needed &= ~ (1 << j);
+ if (needed == 0)
+ return true;
+ }
+ }
+ }
+
+ /* We might get here for two reasons (a) it's a Carmichael number (and hence
+ * composite), or (b) we were just really (un)lucky. We've choosen
+ * NUM_PRIMES big enough so that (b) most likely will never actually
+ * happen. */
+ return false;
+}
+
+
+/* Calculate the gcd, not to be confused with the function in system.h. */
+static uintmax_t euclid (uintmax_t a, uintmax_t b)
+{
+ while (a != 0) {
+ uintmax_t next = b % a;
+ b = a;
+ a = next;
+ }
+ return b;
+}
+
+
+/* The Pollard rho function. We use the usual function x*x+c. The input should
+ * be composite; the function returns a factor. */
+static uintmax_t pollard_rho (uintmax_t n)
+{
+ unsigned iterations = 0;
+ for (unsigned c = 3;; ++c) {
+ uintmax_t slow = c;
+ uintmax_t fast = c * (c + 1);
+ uintmax_t g;
+ while ((g = euclid (slow > fast ? slow - fast : fast - slow, n)) == 1) {
+ slow = add (mult (slow, slow, n), c, n);
+ fast = add (mult (fast, fast, n), c, n);
+ fast = add (mult (fast, fast, n), c, n);
+
+ ++iterations;
+ /* For 64 bits, this gives us 2**24 = 16777216 iterations. If you
+ * ever hit this test, either the code is buggy or your local number
+ * theorist will be amused. */
+ assert (iterations < (1ul << (3 * UINTMAX_BITS / 8)));
+ }
+ if (g != n)
+ return g;
+ }
+}
+
+
+/* Recusively apply Pollard rho until we arrive at prime numbers. */
+static uintmax_t * raw_factorise (uintmax_t n, uintmax_t * factors)
+{
+ if (n <= 1)
+ return factors;
+
+ while (!is_prime (n)) {
+ uintmax_t factor = pollard_rho (n);
+ /* It is arbitrary which of factor and (n/factor) we recurse on. factor
+ * is most likely small (in fact, very often prime), so recursing on
+ * that should limit recursion depth. */
+ factors = raw_factorise (factor, factors);
+ n /= factor;
}
- return n_factors;
+ *factors++ = n;
+ return factors;
}
/* FIXME: comment */
@@ -158,7 +432,7 @@
error (0, 0, _("%s is not a valid positive integer"), quote (s));
return false;
}
- n_factors = factor (n, MAX_N_FACTORS, factors);
+ n_factors = factorise (n, factors);
printf ("%s:", umaxtostr (n, buf));
for (i = 0; i < n_factors; i++)
printf (" %s", umaxtostr (factors[i], buf));
_______________________________________________
Bug-coreutils mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/bug-coreutils