Little fix after the last commit (mostly a git fail)
[eigenmath-fx.git] / divisors.cpp
blobcc9e82b03e53c40041c20795fbba88ba37b631d2
1 #include "stdafx.h"
3 //-----------------------------------------------------------------------------
4 //
5 // Generate all divisors of a term
6 //
7 // Input: Term on stack (factor * factor * ...)
8 //
9 // Output: Divisors on stack
11 //-----------------------------------------------------------------------------
13 #include "defs.h"
15 static void gen(int, int);
16 static void __factor_add(void);
17 static int __cmp(const void *, const void *);
19 void
20 divisors(void)
22 int i, h, n;
23 save();
24 h = tos - 1;
25 divisors_onstack();
26 n = tos - h;
27 qsort(stack + h, n, sizeof (U *), __cmp);
28 p1 = alloc_tensor(n);
29 p1->u.tensor->ndim = 1;
30 p1->u.tensor->dim[0] = n;
31 for (i = 0; i < n; i++)
32 p1->u.tensor->elem[i] = stack[h + i];
33 tos = h;
34 push(p1);
35 restore();
38 void
39 divisors_onstack(void)
41 int h, i, k, n;
43 save();
45 p1 = pop();
47 h = tos;
49 // push all of the term's factors
51 if (isnum(p1)) {
52 push(p1);
53 factor_small_number();
54 } else if (car(p1) == symbol(ADD)) {
55 push(p1);
56 __factor_add();
57 //printf(">>>");
58 //for (i = h; i < tos; i++)
59 //print(stdout, stack[i]);
60 //printf("<<<");
61 } else if (car(p1) == symbol(MULTIPLY)) {
62 p1 = cdr(p1);
63 if (isnum(car(p1))) {
64 push(car(p1));
65 factor_small_number();
66 p1 = cdr(p1);
68 while (iscons(p1)) {
69 p2 = car(p1);
70 if (car(p2) == symbol(POWER)) {
71 push(cadr(p2));
72 push(caddr(p2));
73 } else {
74 push(p2);
75 push(one);
77 p1 = cdr(p1);
79 } else if (car(p1) == symbol(POWER)) {
80 push(cadr(p1));
81 push(caddr(p1));
82 } else {
83 push(p1);
84 push(one);
87 k = tos;
89 // contruct divisors by recursive descent
91 push(one);
93 gen(h, k);
95 // move
97 n = tos - k;
99 for (i = 0; i < n; i++)
100 stack[h + i] = stack[k + i];
102 tos = h + n;
104 restore();
107 //-----------------------------------------------------------------------------
109 // Generate divisors
111 // Input: Base-exponent pairs on stack
113 // h first pair
115 // k just past last pair
117 // Output: Divisors on stack
119 // For example, factor list 2 2 3 1 results in 6 divisors,
121 // 1
122 // 3
123 // 2
124 // 6
125 // 4
126 // 12
128 //-----------------------------------------------------------------------------
130 #define ACCUM p1
131 #define BASE p2
132 #define EXPO p3
134 static void
135 gen(int h, int k)
137 int expo, i;
139 save();
141 ACCUM = pop();
143 if (h == k) {
144 push(ACCUM);
145 restore();
146 return;
149 BASE = stack[h + 0];
150 EXPO = stack[h + 1];
152 push(EXPO);
153 expo = pop_integer();
155 for (i = 0; i <= abs(expo); i++) {
156 push(ACCUM);
157 push(BASE);
158 push_integer(sign(expo) * i);
159 power();
160 multiply();
161 gen(h + 2, k);
164 restore();
167 //-----------------------------------------------------------------------------
169 // Factor ADD expression
171 // Input: Expression on stack
173 // Output: Factors on stack
175 // Each factor consists of two expressions, the factor itself followed
176 // by the exponent.
178 //-----------------------------------------------------------------------------
180 static void
181 __factor_add(void)
183 save();
185 p1 = pop();
187 // get gcd of all terms
189 p3 = cdr(p1);
190 push(car(p3));
191 p3 = cdr(p3);
192 while (iscons(p3)) {
193 push(car(p3));
194 gcd();
195 p3 = cdr(p3);
198 // check gcd
200 p2 = pop();
201 if (isplusone(p2)) {
202 push(p1);
203 push(one);
204 restore();
205 return;
208 // push factored gcd
210 if (isnum(p2)) {
211 push(p2);
212 factor_small_number();
213 } else if (car(p2) == symbol(MULTIPLY)) {
214 p3 = cdr(p2);
215 if (isnum(car(p3))) {
216 push(car(p3));
217 factor_small_number();
218 } else {
219 push(car(p3));
220 push(one);
222 p3 = cdr(p3);
223 while (iscons(p3)) {
224 push(car(p3));
225 push(one);
226 p3 = cdr(p3);
228 } else {
229 push(p2);
230 push(one);
233 // divide each term by gcd
235 push(p2);
236 inverse();
237 p2 = pop();
239 push(zero);
240 p3 = cdr(p1);
241 while (iscons(p3)) {
242 push(p2);
243 push(car(p3));
244 multiply();
245 add();
246 p3 = cdr(p3);
249 push(one);
251 restore();
254 static int
255 __cmp(const void *p1, const void *p2)
257 return cmp_expr(*((U **) p1), *((U **) p2));
260 #if SELFTEST
262 static char *s[] = {
264 "divisors(12)",
265 "(1,2,3,4,6,12)",
267 "divisors(-12)",
268 "(1,2,3,4,6,12)",
270 "divisors(a)",
271 "(1,a)",
273 "divisors(-a)",
274 "(1,a)",
276 "divisors(+3*x+3)",
277 "(1,3,1+x,3+3*x)",
279 "divisors(+3*x-3)",
280 "(1,3,-3+3*x,-1+x)",
282 "divisors(-3*x+3)",
283 "(1,3,1-x,3-3*x)",
285 "divisors(-3*x-3)",
286 "(1,3,1+x,3+3*x)",
289 void
290 test_divisors(void)
292 test(__FILE__, s, sizeof s / sizeof (char *));
295 #endif