This code performs integer factoring using the GMP library, and can also use OpenMP for parallel computation.
I compile it using: gcc -lgmp -fopenmp
and whatever optimization flags I wish to try.
#include <stdio.h>
#include <gmp.h>
void next_prime(MP_INT *x) {
MP_INT r;
mpz_init(&r);
if (!mpz_probab_prime_p(x, 128u)) {
mpz_mod_ui(&r, x, 2ul);
if (mpz_cmp_ui(&r, 0ul) == 0)
mpz_add_ui(x, x, 1ul);
else
mpz_add_ui(x, x, 2ul);
while (!mpz_probab_prime_p(x, 128u)) {
mpz_add_ui(x, x, 2ul);
}
}
mpz_clear(&r);
}
void prev_prime(MP_INT *x) {
MP_INT r;
mpz_init(&r);
if (!mpz_probab_prime_p(x, 128u)) {
mpz_mod_ui(&r, x, 2ul);
if (mpz_cmp_ui(&r, 0ul) == 0)
mpz_sub_ui(x, x, 1ul);
else
mpz_sub_ui(x, x, 2ul);
while (!mpz_probab_prime_p(x, 128u)) {
mpz_sub_ui(x, x, 2ul);
}
}
mpz_clear(&r);
}
unsigned long mp_log(MP_INT *x, MP_INT *base) {
MP_INT r;
mpz_init(&r);
unsigned long lg = 0;
mpz_set(&r, x);
if (base != NULL) {
while (mpz_cmp_ui(&r, 0ul) != 0) {
mpz_div(&r, &r, base);
lg += 1;
}
}
else {
while (mpz_cmp_ui(&r, 0ul) != 0) {
mpz_div_ui(&r, &r, 2ul);
lg += 1;
}
}
mpz_clear(&r);
return lg;
}
void factor(MP_INT *x, MP_INT *n, MP_INT *base) {
/* Initialize variables. */
MP_INT s;
MP_INT r;
mpz_init(&s);
mpz_init(&r);
/* Compute stuff. */
mpz_set(x, n);
if (mpz_probab_prime_p(n, 128u)) {
goto end;
}
mpz_set(&s, base);
mpz_mod(&r, n, &s);
if (mpz_cmp_ui(&r, 0ul) == 0) {
mpz_set(x, &s);
goto end;
}
unsigned long k = mp_log(n, base);
unsigned long a = mp_log(n, NULL);
if (mpz_cmp(x, n) == 0) {
/* Try different powers of n. */
MP_INT p;
mpz_init(&p);
mpz_pow_ui(&p, &s, k);
unsigned long i = 1ul;
while (mpz_cmp(x, n) == 0) {
#pragma omp parallel for
for (unsigned long j = i; j < i + 2*a*a; ++j) {
if (mpz_cmp(x, n) == 0) {
MP_INT g;
mpz_init(&g);
mpz_powm_ui(&g, n, j, &p);
mpz_gcd(&g, &g, n);
if (mpz_cmp_ui(&g, 1ul) != 0 && mpz_cmp(&g, n) != 0) {
mpz_set(x, &g);
}
mpz_clear(&g);
}
}
i += 2*a*a;
}
mpz_clear(&p);
}
/* Clear variables. */
end:
mpz_clear(&s);
mpz_clear(&r);
}
int main() {
char str [65536];
char bas [65536];
while (fscanf(stdin, "%s %s", str, bas) != EOF) {
MP_INT n;
MP_INT base;
mpz_init(&n);
mpz_init(&base);
mpz_set_str(&n, str, 10u);
mpz_set_str(&base, bas, 10u);
mpz_out_str(stdout, 10u, &n);
int p = mpz_probab_prime_p(&n, 128u);
printf(" %d ", p);
mpz_out_str(stdout, 10u, &base);
printf("\n");
while (!p) {
MP_INT x;
mpz_init(&x);
factor(&x, &n, &base);
mpz_out_str(stdout, 10u, &x);
printf(" ");
mpz_div(&n, &n, &x);
p = mpz_probab_prime_p(&n, 128u);
mpz_clear(&x);
}
mpz_out_str(stdout, 10u, &n);
printf("\n");
mpz_clear(&n);
mpz_clear(&base);
}
return 0;
}
next_prime
andprev_prime
? They're unused, and presumably the entry point ismain
. \$\endgroup\$next_prime
andprev_prime
are included is that they were used previously and could be used again, perhaps. \$\endgroup\$base
and check if the gcd with the original input number yields a factor. \$\endgroup\$