pollard.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // Factor using the Pollard rho method
  2. #include "stdafx.h"
  3. #include "defs.h"
  4. static unsigned int *n;
  5. void
  6. factor_number(void)
  7. {
  8. int h;
  9. save();
  10. p1 = pop();
  11. // 0 or 1?
  12. if (equaln(p1, 0) || equaln(p1, 1) || equaln(p1, -1)) {
  13. push(p1);
  14. restore();
  15. return;
  16. }
  17. n = mcopy(p1->u.q.a);
  18. h = tos;
  19. factor_a();
  20. if (tos - h > 1) {
  21. list(tos - h);
  22. push_symbol(MULTIPLY);
  23. swap();
  24. cons();
  25. }
  26. restore();
  27. }
  28. // factor using table look-up, then switch to rho method if necessary
  29. // From TAOCP Vol. 2 by Knuth, p. 380 (Algorithm A)
  30. void
  31. factor_a(void)
  32. {
  33. int k;
  34. if (MSIGN(n) == -1) {
  35. MSIGN(n) = 1;
  36. push_integer(-1);
  37. }
  38. for (k = 0; k < 10000; k++) {
  39. try_kth_prime(k);
  40. // if n is 1 then we're done
  41. if (MLENGTH(n) == 1 && n[0] == 1) {
  42. mfree(n);
  43. return;
  44. }
  45. }
  46. factor_b();
  47. }
  48. void
  49. try_kth_prime(int k)
  50. {
  51. int count;
  52. unsigned int *d, *q, *r;
  53. d = mint(primetab[k]);
  54. count = 0;
  55. while (1) {
  56. // if n is 1 then we're done
  57. if (MLENGTH(n) == 1 && n[0] == 1) {
  58. if (count)
  59. push_factor(d, count);
  60. else
  61. mfree(d);
  62. return;
  63. }
  64. mdivrem(&q, &r, n, d);
  65. // continue looping while remainder is zero
  66. if (MLENGTH(r) == 1 && r[0] == 0) {
  67. count++;
  68. mfree(r);
  69. mfree(n);
  70. n = q;
  71. } else {
  72. mfree(r);
  73. break;
  74. }
  75. }
  76. if (count)
  77. push_factor(d, count);
  78. // q = n/d, hence if q < d then n < d^2 so n is prime
  79. if (mcmp(q, d) == -1) {
  80. push_factor(n, 1);
  81. n = mint(1);
  82. }
  83. if (count == 0)
  84. mfree(d);
  85. mfree(q);
  86. }
  87. // From TAOCP Vol. 2 by Knuth, p. 385 (Algorithm B)
  88. int
  89. factor_b(void)
  90. {
  91. int k, l;
  92. unsigned int *g, *one, *t, *x, *xprime;
  93. one = mint(1);
  94. x = mint(5);
  95. xprime = mint(2);
  96. k = 1;
  97. l = 1;
  98. while (1) {
  99. if (mprime(n)) {
  100. push_factor(n, 1);
  101. mfree(one);
  102. mfree(x);
  103. mfree(xprime);
  104. return 0;
  105. }
  106. while (1) {
  107. if (esc_flag) {
  108. mfree(one);
  109. mfree(n);
  110. mfree(x);
  111. mfree(xprime);
  112. stop("esc");
  113. }
  114. // g = gcd(x' - x, n)
  115. t = msub(xprime, x);
  116. MSIGN(t) = 1;
  117. g = mgcd(t, n);
  118. mfree(t);
  119. if (MEQUAL(g, 1)) {
  120. mfree(g);
  121. if (--k == 0) {
  122. mfree(xprime);
  123. xprime = mcopy(x);
  124. l *= 2;
  125. k = l;
  126. }
  127. // x = (x ^ 2 + 1) mod n
  128. t = mmul(x, x);
  129. mfree(x);
  130. x = madd(t, one);
  131. mfree(t);
  132. t = mmod(x, n);
  133. mfree(x);
  134. x = t;
  135. continue;
  136. }
  137. push_factor(g, 1);
  138. if (mcmp(g, n) == 0) {
  139. mfree(one);
  140. mfree(n);
  141. mfree(x);
  142. mfree(xprime);
  143. return -1;
  144. }
  145. // n = n / g
  146. t = mdiv(n, g);
  147. mfree(n);
  148. n = t;
  149. // x = x mod n
  150. t = mmod(x, n);
  151. mfree(x);
  152. x = t;
  153. // xprime = xprime mod n
  154. t = mmod(xprime, n);
  155. mfree(xprime);
  156. xprime = t;
  157. break;
  158. }
  159. }
  160. }
  161. void
  162. push_factor(unsigned int *d, int count)
  163. {
  164. p1 = alloc();
  165. p1->k = NUM;
  166. p1->u.q.a = d;
  167. p1->u.q.b = mint(1);
  168. push(p1);
  169. if (count > 1) {
  170. push_symbol(POWER);
  171. swap();
  172. p1 = alloc();
  173. p1->k = NUM;
  174. p1->u.q.a = mint(count);
  175. p1->u.q.b = mint(1);
  176. push(p1);
  177. list(3);
  178. }
  179. }