Little fix after the last commit (mostly a git fail)
[eigenmath-fx.git] / pollard.cpp
blob18d3ac8278b0513307604f3f0cf4f81f9a9d460c
1 // Factor using the Pollard rho method
3 #include "stdafx.h"
4 #include "defs.h"
6 static unsigned int *n;
8 void
9 factor_number(void)
11 int h;
13 save();
15 p1 = pop();
17 // 0 or 1?
19 if (equaln(p1, 0) || equaln(p1, 1) || equaln(p1, -1)) {
20 push(p1);
21 restore();
22 return;
25 n = mcopy(p1->u.q.a);
27 h = tos;
29 factor_a();
31 if (tos - h > 1) {
32 list(tos - h);
33 push_symbol(MULTIPLY);
34 swap();
35 cons();
38 restore();
41 // factor using table look-up, then switch to rho method if necessary
43 // From TAOCP Vol. 2 by Knuth, p. 380 (Algorithm A)
45 void
46 factor_a(void)
48 int k;
50 if (MSIGN(n) == -1) {
51 MSIGN(n) = 1;
52 push_integer(-1);
55 for (k = 0; k < 10000; k++) {
57 try_kth_prime(k);
59 // if n is 1 then we're done
61 if (MLENGTH(n) == 1 && n[0] == 1) {
62 mfree(n);
63 return;
67 factor_b();
70 void
71 try_kth_prime(int k)
73 int count;
74 unsigned int *d, *q, *r;
76 d = mint(primetab[k]);
78 count = 0;
80 while (1) {
82 // if n is 1 then we're done
84 if (MLENGTH(n) == 1 && n[0] == 1) {
85 if (count)
86 push_factor(d, count);
87 else
88 mfree(d);
89 return;
92 mdivrem(&q, &r, n, d);
94 // continue looping while remainder is zero
96 if (MLENGTH(r) == 1 && r[0] == 0) {
97 count++;
98 mfree(r);
99 mfree(n);
100 n = q;
101 } else {
102 mfree(r);
103 break;
107 if (count)
108 push_factor(d, count);
110 // q = n/d, hence if q < d then n < d^2 so n is prime
112 if (mcmp(q, d) == -1) {
113 push_factor(n, 1);
114 n = mint(1);
117 if (count == 0)
118 mfree(d);
120 mfree(q);
123 // From TAOCP Vol. 2 by Knuth, p. 385 (Algorithm B)
126 factor_b(void)
128 int k, l;
129 unsigned int *g, *one, *t, *x, *xprime;
131 one = mint(1);
132 x = mint(5);
133 xprime = mint(2);
135 k = 1;
136 l = 1;
138 while (1) {
140 if (mprime(n)) {
141 push_factor(n, 1);
142 mfree(one);
143 mfree(x);
144 mfree(xprime);
145 return 0;
148 while (1) {
150 if (esc_flag) {
151 mfree(one);
152 mfree(n);
153 mfree(x);
154 mfree(xprime);
155 stop("esc");
158 // g = gcd(x' - x, n)
160 t = msub(xprime, x);
161 MSIGN(t) = 1;
162 g = mgcd(t, n);
163 mfree(t);
165 if (MEQUAL(g, 1)) {
166 mfree(g);
167 if (--k == 0) {
168 mfree(xprime);
169 xprime = mcopy(x);
170 l *= 2;
171 k = l;
174 // x = (x ^ 2 + 1) mod n
176 t = mmul(x, x);
177 mfree(x);
178 x = madd(t, one);
179 mfree(t);
180 t = mmod(x, n);
181 mfree(x);
182 x = t;
184 continue;
187 push_factor(g, 1);
189 if (mcmp(g, n) == 0) {
190 mfree(one);
191 mfree(n);
192 mfree(x);
193 mfree(xprime);
194 return -1;
197 // n = n / g
199 t = mdiv(n, g);
200 mfree(n);
201 n = t;
203 // x = x mod n
205 t = mmod(x, n);
206 mfree(x);
207 x = t;
209 // xprime = xprime mod n
211 t = mmod(xprime, n);
212 mfree(xprime);
213 xprime = t;
215 break;
220 void
221 push_factor(unsigned int *d, int count)
223 p1 = alloc();
224 p1->k = NUM;
225 p1->u.q.a = d;
226 p1->u.q.b = mint(1);
227 push(p1);
228 if (count > 1) {
229 push_symbol(POWER);
230 swap();
231 p1 = alloc();
232 p1->k = NUM;
233 p1->u.q.a = mint(count);
234 p1->u.q.b = mint(1);
235 push(p1);
236 list(3);