gcd.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. // Greatest common denominator
  2. #include "stdafx.h"
  3. #include "defs.h"
  4. void
  5. eval_gcd(void)
  6. {
  7. p1 = cdr(p1);
  8. push(car(p1));
  9. eval();
  10. p1 = cdr(p1);
  11. while (iscons(p1)) {
  12. push(car(p1));
  13. eval();
  14. gcd();
  15. p1 = cdr(p1);
  16. }
  17. }
  18. void
  19. gcd(void)
  20. {
  21. int x = expanding;
  22. save();
  23. gcd_main();
  24. restore();
  25. expanding = x;
  26. }
  27. void
  28. gcd_main(void)
  29. {
  30. expanding = 1;
  31. p2 = pop();
  32. p1 = pop();
  33. if (equal(p1, p2)) {
  34. push(p1);
  35. return;
  36. }
  37. if (isrational(p1) && isrational(p2)) {
  38. push(p1);
  39. push(p2);
  40. gcd_numbers();
  41. return;
  42. }
  43. if (car(p1) == symbol(ADD) && car(p2) == symbol(ADD)) {
  44. gcd_expr_expr();
  45. return;
  46. }
  47. if (car(p1) == symbol(ADD)) {
  48. gcd_expr(p1);
  49. p1 = pop();
  50. }
  51. if (car(p2) == symbol(ADD)) {
  52. gcd_expr(p2);
  53. p2 = pop();
  54. }
  55. if (car(p1) == symbol(MULTIPLY) && car(p2) == symbol(MULTIPLY)) {
  56. gcd_term_term();
  57. return;
  58. }
  59. if (car(p1) == symbol(MULTIPLY)) {
  60. gcd_term_factor();
  61. return;
  62. }
  63. if (car(p2) == symbol(MULTIPLY)) {
  64. gcd_factor_term();
  65. return;
  66. }
  67. // gcd of factors
  68. if (car(p1) == symbol(POWER)) {
  69. p3 = caddr(p1);
  70. p1 = cadr(p1);
  71. } else
  72. p3 = one;
  73. if (car(p2) == symbol(POWER)) {
  74. p4 = caddr(p2);
  75. p2 = cadr(p2);
  76. } else
  77. p4 = one;
  78. if (!equal(p1, p2)) {
  79. push(one);
  80. return;
  81. }
  82. // are both exponents numerical?
  83. if (isnum(p3) && isnum(p4)) {
  84. push(p1);
  85. if (lessp(p3, p4))
  86. push(p3);
  87. else
  88. push(p4);
  89. power();
  90. return;
  91. }
  92. // are the exponents multiples of eah other?
  93. push(p3);
  94. push(p4);
  95. divide();
  96. p5 = pop();
  97. if (isnum(p5)) {
  98. push(p1);
  99. // choose the smallest exponent
  100. if (car(p3) == symbol(MULTIPLY) && isnum(cadr(p3)))
  101. p5 = cadr(p3);
  102. else
  103. p5 = one;
  104. if (car(p4) == symbol(MULTIPLY) && isnum(cadr(p4)))
  105. p6 = cadr(p4);
  106. else
  107. p6 = one;
  108. if (lessp(p5, p6))
  109. push(p3);
  110. else
  111. push(p4);
  112. power();
  113. return;
  114. }
  115. push(p3);
  116. push(p4);
  117. subtract();
  118. p5 = pop();
  119. if (!isnum(p5)) {
  120. push(one);
  121. return;
  122. }
  123. // can't be equal because of test near beginning
  124. push(p1);
  125. if (isnegativenumber(p5))
  126. push(p3);
  127. else
  128. push(p4);
  129. power();
  130. }
  131. // in this case gcd is used as a composite function, i.e. gcd(gcd(gcd...
  132. void
  133. gcd_expr_expr(void)
  134. {
  135. if (length(p1) != length(p2)) {
  136. push(one);
  137. return;
  138. }
  139. p3 = cdr(p1);
  140. push(car(p3));
  141. p3 = cdr(p3);
  142. while (iscons(p3)) {
  143. push(car(p3));
  144. gcd();
  145. p3 = cdr(p3);
  146. }
  147. p3 = pop();
  148. p4 = cdr(p2);
  149. push(car(p4));
  150. p4 = cdr(p4);
  151. while (iscons(p4)) {
  152. push(car(p4));
  153. gcd();
  154. p4 = cdr(p4);
  155. }
  156. p4 = pop();
  157. push(p1);
  158. push(p3);
  159. divide();
  160. p5 = pop();
  161. push(p2);
  162. push(p4);
  163. divide();
  164. p6 = pop();
  165. if (equal(p5, p6)) {
  166. push(p5);
  167. push(p3);
  168. push(p4);
  169. gcd();
  170. multiply();
  171. } else
  172. push(one);
  173. }
  174. void
  175. gcd_expr(U *p)
  176. {
  177. p = cdr(p);
  178. push(car(p));
  179. p = cdr(p);
  180. while (iscons(p)) {
  181. push(car(p));
  182. gcd();
  183. p = cdr(p);
  184. }
  185. }
  186. void
  187. gcd_term_term(void)
  188. {
  189. push(one);
  190. p3 = cdr(p1);
  191. while (iscons(p3)) {
  192. p4 = cdr(p2);
  193. while (iscons(p4)) {
  194. push(car(p3));
  195. push(car(p4));
  196. gcd();
  197. multiply();
  198. p4 = cdr(p4);
  199. }
  200. p3 = cdr(p3);
  201. }
  202. }
  203. void
  204. gcd_term_factor(void)
  205. {
  206. push(one);
  207. p3 = cdr(p1);
  208. while (iscons(p3)) {
  209. push(car(p3));
  210. push(p2);
  211. gcd();
  212. multiply();
  213. p3 = cdr(p3);
  214. }
  215. }
  216. void
  217. gcd_factor_term(void)
  218. {
  219. push(one);
  220. p4 = cdr(p2);
  221. while (iscons(p4)) {
  222. push(p1);
  223. push(car(p4));
  224. gcd();
  225. multiply();
  226. p4 = cdr(p4);
  227. }
  228. }
  229. #if SELFTEST
  230. static char *s[] = {
  231. "gcd(30,42)",
  232. "6",
  233. "gcd(42,30)",
  234. "6",
  235. "gcd(-30,42)",
  236. "6",
  237. "gcd(42,-30)",
  238. "6",
  239. "gcd(30,-42)",
  240. "6",
  241. "gcd(-42,30)",
  242. "6",
  243. "gcd(-30,-42)",
  244. "6",
  245. "gcd(-42,-30)",
  246. "6",
  247. "gcd(x,x)",
  248. "x",
  249. "gcd(-x,x)",
  250. "x",
  251. "gcd(x,-x)",
  252. "x",
  253. "gcd(-x,-x)",
  254. "-x",
  255. "gcd(x^2,x^3)",
  256. "x^2",
  257. "gcd(x,y)",
  258. "1",
  259. "gcd(y,x)",
  260. "1",
  261. "gcd(x*y,y)",
  262. "y",
  263. "gcd(x*y,y^2)",
  264. "y",
  265. "gcd(x^2*y^2,x^3*y^3)",
  266. "x^2*y^2",
  267. "gcd(x^2,x^3)",
  268. "x^2",
  269. // gcd of expr
  270. "gcd(x+y,x+z)",
  271. "1",
  272. "gcd(x+y,x+y)",
  273. "x+y",
  274. "gcd(x+y,2*x+2*y)",
  275. "x+y",
  276. "gcd(-x-y,x+y)",
  277. "x+y",
  278. "gcd(4*x+4*y,6*x+6*y)",
  279. "2*x+2*y",
  280. "gcd(4*x+4*y+4,6*x+6*y+6)",
  281. "2+2*x+2*y",
  282. "gcd(4*x+4*y+4,6*x+6*y+12)",
  283. "1",
  284. "gcd(27*t^3+y^3+9*t*y^2+27*t^2*y,t+y)",
  285. "1",
  286. // gcd expr factor
  287. "gcd(2*a^2*x^2+a*x+a*b,a)",
  288. "a",
  289. "gcd(2*a^2*x^2+a*x+a*b,a^2)",
  290. "a",
  291. "gcd(2*a^2*x^2+2*a*x+2*a*b,a)",
  292. "a",
  293. // gcd expr term
  294. "gcd(2*a^2*x^2+2*a*x+2*a*b,2*a)",
  295. "2*a",
  296. "gcd(2*a^2*x^2+2*a*x+2*a*b,3*a)",
  297. "a",
  298. "gcd(2*a^2*x^2+2*a*x+2*a*b,4*a)",
  299. "2*a",
  300. // gcd factor factor
  301. "gcd(x,x^2)",
  302. "x",
  303. "gcd(x,x^a)",
  304. "1",
  305. // multiple arguments
  306. "gcd(12,18,9)",
  307. "3",
  308. };
  309. void
  310. test_gcd(void)
  311. {
  312. test(__FILE__, s, sizeof s / sizeof (char *));
  313. }
  314. #endif