2004-03-03 21:24:06 +01:00
|
|
|
// Factor using the Pollard rho method
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "defs.h"
|
2006-01-16 20:37:31 +01:00
|
|
|
|
2007-11-22 01:28:04 +01:00
|
|
|
static unsigned int *n;
|
2004-03-03 21:24:06 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
factor_number(void)
|
|
|
|
{
|
|
|
|
int h;
|
|
|
|
|
|
|
|
save();
|
|
|
|
|
|
|
|
p1 = pop();
|
|
|
|
|
2007-11-22 01:28:04 +01:00
|
|
|
// 0 or 1?
|
2004-03-03 21:24:06 +01:00
|
|
|
|
2007-11-22 01:28:04 +01:00
|
|
|
if (equaln(p1, 0) || equaln(p1, 1) || equaln(p1, -1)) {
|
2004-03-03 21:24:06 +01:00
|
|
|
push(p1);
|
|
|
|
restore();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-11-22 01:28:04 +01:00
|
|
|
n = mcopy(p1->u.q.a);
|
|
|
|
|
2004-03-03 21:24:06 +01:00
|
|
|
h = tos;
|
|
|
|
|
2007-11-22 01:28:04 +01:00
|
|
|
factor_a();
|
2004-03-03 21:24:06 +01:00
|
|
|
|
|
|
|
if (tos - h > 1) {
|
|
|
|
list(tos - h);
|
|
|
|
push_symbol(MULTIPLY);
|
|
|
|
swap();
|
|
|
|
cons();
|
|
|
|
}
|
|
|
|
|
|
|
|
restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
// factor using table look-up, then switch to rho method if necessary
|
|
|
|
|
|
|
|
// From TAOCP Vol. 2 by Knuth, p. 380 (Algorithm A)
|
|
|
|
|
2007-11-22 01:28:04 +01:00
|
|
|
void
|
|
|
|
factor_a(void)
|
2004-03-03 21:24:06 +01:00
|
|
|
{
|
|
|
|
int k;
|
|
|
|
|
|
|
|
if (MSIGN(n) == -1) {
|
|
|
|
MSIGN(n) = 1;
|
|
|
|
push_integer(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (k = 0; k < 10000; k++) {
|
|
|
|
|
2007-11-22 01:28:04 +01:00
|
|
|
try_kth_prime(k);
|
2004-03-03 21:24:06 +01:00
|
|
|
|
|
|
|
// if n is 1 then we're done
|
|
|
|
|
|
|
|
if (MLENGTH(n) == 1 && n[0] == 1) {
|
|
|
|
mfree(n);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-22 01:28:04 +01:00
|
|
|
factor_b();
|
2004-03-03 21:24:06 +01:00
|
|
|
}
|
|
|
|
|
2007-11-22 01:28:04 +01:00
|
|
|
void
|
|
|
|
try_kth_prime(int k)
|
2004-03-03 21:24:06 +01:00
|
|
|
{
|
|
|
|
int count;
|
|
|
|
unsigned int *d, *q, *r;
|
|
|
|
|
|
|
|
d = mint(primetab[k]);
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
|
|
|
// if n is 1 then we're done
|
|
|
|
|
2007-11-22 01:28:04 +01:00
|
|
|
if (MLENGTH(n) == 1 && n[0] == 1) {
|
2004-03-03 21:24:06 +01:00
|
|
|
if (count)
|
|
|
|
push_factor(d, count);
|
|
|
|
else
|
|
|
|
mfree(d);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-11-22 01:28:04 +01:00
|
|
|
mdivrem(&q, &r, n, d);
|
2004-03-03 21:24:06 +01:00
|
|
|
|
|
|
|
// continue looping while remainder is zero
|
|
|
|
|
|
|
|
if (MLENGTH(r) == 1 && r[0] == 0) {
|
|
|
|
count++;
|
|
|
|
mfree(r);
|
2007-11-22 01:28:04 +01:00
|
|
|
mfree(n);
|
|
|
|
n = q;
|
2004-03-03 21:24:06 +01:00
|
|
|
} else {
|
|
|
|
mfree(r);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count)
|
|
|
|
push_factor(d, count);
|
|
|
|
|
2007-11-22 01:28:04 +01:00
|
|
|
// q = n/d, hence if q < d then n < d^2 so n is prime
|
2004-03-03 21:24:06 +01:00
|
|
|
|
|
|
|
if (mcmp(q, d) == -1) {
|
2007-11-22 01:28:04 +01:00
|
|
|
push_factor(n, 1);
|
|
|
|
n = mint(1);
|
2004-03-03 21:24:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (count == 0)
|
|
|
|
mfree(d);
|
|
|
|
|
|
|
|
mfree(q);
|
|
|
|
}
|
|
|
|
|
|
|
|
// From TAOCP Vol. 2 by Knuth, p. 385 (Algorithm B)
|
|
|
|
|
2007-11-22 01:28:04 +01:00
|
|
|
int
|
|
|
|
factor_b(void)
|
2004-03-03 21:24:06 +01:00
|
|
|
{
|
|
|
|
int k, l;
|
|
|
|
unsigned int *g, *one, *t, *x, *xprime;
|
|
|
|
|
|
|
|
one = mint(1);
|
|
|
|
x = mint(5);
|
|
|
|
xprime = mint(2);
|
|
|
|
|
|
|
|
k = 1;
|
|
|
|
l = 1;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
|
|
|
if (mprime(n)) {
|
2007-11-22 01:28:04 +01:00
|
|
|
push_factor(n, 1);
|
2004-03-03 21:24:06 +01:00
|
|
|
mfree(one);
|
|
|
|
mfree(x);
|
|
|
|
mfree(xprime);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
|
|
|
if (esc_flag) {
|
|
|
|
mfree(one);
|
2007-11-22 01:28:04 +01:00
|
|
|
mfree(n);
|
2004-03-03 21:24:06 +01:00
|
|
|
mfree(x);
|
|
|
|
mfree(xprime);
|
|
|
|
stop("esc");
|
|
|
|
}
|
|
|
|
|
|
|
|
// g = gcd(x' - x, n)
|
|
|
|
|
|
|
|
t = msub(xprime, x);
|
|
|
|
MSIGN(t) = 1;
|
|
|
|
g = mgcd(t, n);
|
|
|
|
mfree(t);
|
|
|
|
|
|
|
|
if (MEQUAL(g, 1)) {
|
|
|
|
mfree(g);
|
|
|
|
if (--k == 0) {
|
|
|
|
mfree(xprime);
|
|
|
|
xprime = mcopy(x);
|
|
|
|
l *= 2;
|
|
|
|
k = l;
|
|
|
|
}
|
|
|
|
|
|
|
|
// x = (x ^ 2 + 1) mod n
|
|
|
|
|
|
|
|
t = mmul(x, x);
|
|
|
|
mfree(x);
|
|
|
|
x = madd(t, one);
|
|
|
|
mfree(t);
|
|
|
|
t = mmod(x, n);
|
|
|
|
mfree(x);
|
|
|
|
x = t;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-11-22 01:28:04 +01:00
|
|
|
push_factor(g, 1);
|
2004-03-03 21:24:06 +01:00
|
|
|
|
|
|
|
if (mcmp(g, n) == 0) {
|
|
|
|
mfree(one);
|
|
|
|
mfree(n);
|
|
|
|
mfree(x);
|
|
|
|
mfree(xprime);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// n = n / g
|
|
|
|
|
|
|
|
t = mdiv(n, g);
|
|
|
|
mfree(n);
|
|
|
|
n = t;
|
|
|
|
|
|
|
|
// x = x mod n
|
|
|
|
|
|
|
|
t = mmod(x, n);
|
|
|
|
mfree(x);
|
|
|
|
x = t;
|
|
|
|
|
|
|
|
// xprime = xprime mod n
|
|
|
|
|
|
|
|
t = mmod(xprime, n);
|
|
|
|
mfree(xprime);
|
|
|
|
xprime = t;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-11-22 01:28:04 +01:00
|
|
|
push_factor(unsigned int *d, int count)
|
2004-03-03 21:24:06 +01:00
|
|
|
{
|
|
|
|
p1 = alloc();
|
|
|
|
p1->k = NUM;
|
2007-11-22 01:28:04 +01:00
|
|
|
p1->u.q.a = d;
|
2004-03-03 21:24:06 +01:00
|
|
|
p1->u.q.b = mint(1);
|
2007-11-22 01:28:04 +01:00
|
|
|
push(p1);
|
|
|
|
if (count > 1) {
|
|
|
|
push_symbol(POWER);
|
|
|
|
swap();
|
|
|
|
p1 = alloc();
|
|
|
|
p1->k = NUM;
|
|
|
|
p1->u.q.a = mint(count);
|
|
|
|
p1->u.q.b = mint(1);
|
2004-03-03 21:24:06 +01:00
|
|
|
push(p1);
|
2007-11-22 01:28:04 +01:00
|
|
|
list(3);
|
2004-03-03 21:24:06 +01:00
|
|
|
}
|
|
|
|
}
|