Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
Project: cocalc-sagemath-dev-slelievre
Views: 418346/* Factoring with Pollard's rho method.12Copyright 1995, 1997-2003, 2005, 2009, 2012 Free Software Foundation, Inc.34This program is free software; you can redistribute it and/or modify it under5the terms of the GNU General Public License as published by the Free Software6Foundation; either version 3 of the License, or (at your option) any later7version.89This program is distributed in the hope that it will be useful, but WITHOUT ANY10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A11PARTICULAR PURPOSE. See the GNU General Public License for more details.1213You should have received a copy of the GNU General Public License along with14this program. If not, see https://www.gnu.org/licenses/. */151617#include <stdlib.h>18#include <stdio.h>19#include <string.h>20#include <inttypes.h>2122#include "gmp.h"2324static unsigned char primes_diff[] = {25#define P(a,b,c) a,26#include "primes.h"27#undef P28};29#define PRIMES_PTAB_ENTRIES (sizeof(primes_diff) / sizeof(primes_diff[0]))3031int flag_verbose = 0;3233/* Prove primality or run probabilistic tests. */34int flag_prove_primality = 1;3536/* Number of Miller-Rabin tests to run when not proving primality. */37#define MR_REPS 253839struct factors40{41mpz_t *p;42unsigned long *e;43long nfactors;44};4546void factor (mpz_t, struct factors *);4748void49factor_init (struct factors *factors)50{51factors->p = malloc (1);52factors->e = malloc (1);53factors->nfactors = 0;54}5556void57factor_clear (struct factors *factors)58{59int i;6061for (i = 0; i < factors->nfactors; i++)62mpz_clear (factors->p[i]);6364free (factors->p);65free (factors->e);66}6768void69factor_insert (struct factors *factors, mpz_t prime)70{71long nfactors = factors->nfactors;72mpz_t *p = factors->p;73unsigned long *e = factors->e;74long i, j;7576/* Locate position for insert new or increment e. */77for (i = nfactors - 1; i >= 0; i--)78{79if (mpz_cmp (p[i], prime) <= 0)80break;81}8283if (i < 0 || mpz_cmp (p[i], prime) != 0)84{85p = realloc (p, (nfactors + 1) * sizeof p[0]);86e = realloc (e, (nfactors + 1) * sizeof e[0]);8788mpz_init (p[nfactors]);89for (j = nfactors - 1; j > i; j--)90{91mpz_set (p[j + 1], p[j]);92e[j + 1] = e[j];93}94mpz_set (p[i + 1], prime);95e[i + 1] = 1;9697factors->p = p;98factors->e = e;99factors->nfactors = nfactors + 1;100}101else102{103e[i] += 1;104}105}106107void108factor_insert_ui (struct factors *factors, unsigned long prime)109{110mpz_t pz;111112mpz_init_set_ui (pz, prime);113factor_insert (factors, pz);114mpz_clear (pz);115}116117118void119factor_using_division (mpz_t t, struct factors *factors)120{121mpz_t q;122unsigned long int p;123int i;124125if (flag_verbose > 0)126{127printf ("[trial division] ");128}129130mpz_init (q);131132p = mpz_scan1 (t, 0);133mpz_div_2exp (t, t, p);134while (p)135{136factor_insert_ui (factors, 2);137--p;138}139140p = 3;141for (i = 1; i <= PRIMES_PTAB_ENTRIES;)142{143if (! mpz_divisible_ui_p (t, p))144{145p += primes_diff[i++];146if (mpz_cmp_ui (t, p * p) < 0)147break;148}149else150{151mpz_tdiv_q_ui (t, t, p);152factor_insert_ui (factors, p);153}154}155156mpz_clear (q);157}158159static int160mp_millerrabin (mpz_srcptr n, mpz_srcptr nm1, mpz_ptr x, mpz_ptr y,161mpz_srcptr q, unsigned long int k)162{163unsigned long int i;164165mpz_powm (y, x, q, n);166167if (mpz_cmp_ui (y, 1) == 0 || mpz_cmp (y, nm1) == 0)168return 1;169170for (i = 1; i < k; i++)171{172mpz_powm_ui (y, y, 2, n);173if (mpz_cmp (y, nm1) == 0)174return 1;175if (mpz_cmp_ui (y, 1) == 0)176return 0;177}178return 0;179}180181int182mp_prime_p (mpz_t n)183{184int k, r, is_prime;185mpz_t q, a, nm1, tmp;186struct factors factors;187188if (mpz_cmp_ui (n, 1) <= 0)189return 0;190191/* We have already casted out small primes. */192if (mpz_cmp_ui (n, (long) FIRST_OMITTED_PRIME * FIRST_OMITTED_PRIME) < 0)193return 1;194195mpz_inits (q, a, nm1, tmp, NULL);196197/* Precomputation for Miller-Rabin. */198mpz_sub_ui (nm1, n, 1);199200/* Find q and k, where q is odd and n = 1 + 2**k * q. */201k = mpz_scan1 (nm1, 0);202mpz_tdiv_q_2exp (q, nm1, k);203204mpz_set_ui (a, 2);205206/* Perform a Miller-Rabin test, finds most composites quickly. */207if (!mp_millerrabin (n, nm1, a, tmp, q, k))208{209is_prime = 0;210goto ret2;211}212213if (flag_prove_primality)214{215/* Factor n-1 for Lucas. */216mpz_set (tmp, nm1);217factor (tmp, &factors);218}219220/* Loop until Lucas proves our number prime, or Miller-Rabin proves our221number composite. */222for (r = 0; r < PRIMES_PTAB_ENTRIES; r++)223{224int i;225226if (flag_prove_primality)227{228is_prime = 1;229for (i = 0; i < factors.nfactors && is_prime; i++)230{231mpz_divexact (tmp, nm1, factors.p[i]);232mpz_powm (tmp, a, tmp, n);233is_prime = mpz_cmp_ui (tmp, 1) != 0;234}235}236else237{238/* After enough Miller-Rabin runs, be content. */239is_prime = (r == MR_REPS - 1);240}241242if (is_prime)243goto ret1;244245mpz_add_ui (a, a, primes_diff[r]); /* Establish new base. */246247if (!mp_millerrabin (n, nm1, a, tmp, q, k))248{249is_prime = 0;250goto ret1;251}252}253254fprintf (stderr, "Lucas prime test failure. This should not happen\n");255abort ();256257ret1:258if (flag_prove_primality)259factor_clear (&factors);260ret2:261mpz_clears (q, a, nm1, tmp, NULL);262263return is_prime;264}265266void267factor_using_pollard_rho (mpz_t n, unsigned long a, struct factors *factors)268{269mpz_t x, z, y, P;270mpz_t t, t2;271unsigned long long k, l, i;272273if (flag_verbose > 0)274{275printf ("[pollard-rho (%lu)] ", a);276}277278mpz_inits (t, t2, NULL);279mpz_init_set_si (y, 2);280mpz_init_set_si (x, 2);281mpz_init_set_si (z, 2);282mpz_init_set_ui (P, 1);283k = 1;284l = 1;285286while (mpz_cmp_ui (n, 1) != 0)287{288for (;;)289{290do291{292mpz_mul (t, x, x);293mpz_mod (x, t, n);294mpz_add_ui (x, x, a);295296mpz_sub (t, z, x);297mpz_mul (t2, P, t);298mpz_mod (P, t2, n);299300if (k % 32 == 1)301{302mpz_gcd (t, P, n);303if (mpz_cmp_ui (t, 1) != 0)304goto factor_found;305mpz_set (y, x);306}307}308while (--k != 0);309310mpz_set (z, x);311k = l;312l = 2 * l;313for (i = 0; i < k; i++)314{315mpz_mul (t, x, x);316mpz_mod (x, t, n);317mpz_add_ui (x, x, a);318}319mpz_set (y, x);320}321322factor_found:323do324{325mpz_mul (t, y, y);326mpz_mod (y, t, n);327mpz_add_ui (y, y, a);328329mpz_sub (t, z, y);330mpz_gcd (t, t, n);331}332while (mpz_cmp_ui (t, 1) == 0);333334mpz_divexact (n, n, t); /* divide by t, before t is overwritten */335336if (!mp_prime_p (t))337{338if (flag_verbose > 0)339{340printf ("[composite factor--restarting pollard-rho] ");341}342factor_using_pollard_rho (t, a + 1, factors);343}344else345{346factor_insert (factors, t);347}348349if (mp_prime_p (n))350{351factor_insert (factors, n);352break;353}354355mpz_mod (x, x, n);356mpz_mod (z, z, n);357mpz_mod (y, y, n);358}359360mpz_clears (P, t2, t, z, x, y, NULL);361}362363void364factor (mpz_t t, struct factors *factors)365{366factor_init (factors);367368if (mpz_sgn (t) != 0)369{370factor_using_division (t, factors);371372if (mpz_cmp_ui (t, 1) != 0)373{374if (flag_verbose > 0)375{376printf ("[is number prime?] ");377}378if (mp_prime_p (t))379factor_insert (factors, t);380else381factor_using_pollard_rho (t, 1, factors);382}383}384}385386int387main (int argc, char *argv[])388{389mpz_t t;390int i, j, k;391struct factors factors;392393while (argc > 1)394{395if (!strcmp (argv[1], "-v"))396flag_verbose = 1;397else if (!strcmp (argv[1], "-w"))398flag_prove_primality = 0;399else400break;401402argv++;403argc--;404}405406mpz_init (t);407if (argc > 1)408{409for (i = 1; i < argc; i++)410{411mpz_set_str (t, argv[i], 0);412413gmp_printf ("%Zd:", t);414factor (t, &factors);415416for (j = 0; j < factors.nfactors; j++)417for (k = 0; k < factors.e[j]; k++)418gmp_printf (" %Zd", factors.p[j]);419420puts ("");421factor_clear (&factors);422}423}424else425{426for (;;)427{428mpz_inp_str (t, stdin, 0);429if (feof (stdin))430break;431432gmp_printf ("%Zd:", t);433factor (t, &factors);434435for (j = 0; j < factors.nfactors; j++)436for (k = 0; k < factors.e[j]; k++)437gmp_printf (" %Zd", factors.p[j]);438439puts ("");440factor_clear (&factors);441}442}443444exit (0);445}446447448