405 lines
4.7 KiB
C++
405 lines
4.7 KiB
C++
|
#include "stdafx.h"
|
||
|
|
||
|
|
||
|
#include "defs.h"
|
||
|
|
||
|
#define DEBUG 0
|
||
|
|
||
|
static void __gcd(void);
|
||
|
static void gcd_expr_expr(void);
|
||
|
static void gcd_expr(U *);
|
||
|
static void gcd_term_term(void);
|
||
|
static void gcd_term_factor(void);
|
||
|
static void gcd_factor_term(void);
|
||
|
|
||
|
void
|
||
|
gcd(void)
|
||
|
{
|
||
|
int x = expanding;
|
||
|
save();
|
||
|
__gcd();
|
||
|
restore();
|
||
|
expanding = x;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
__gcd(void)
|
||
|
{
|
||
|
expanding = 1;
|
||
|
|
||
|
p2 = pop();
|
||
|
p1 = pop();
|
||
|
|
||
|
#if DEBUG
|
||
|
printf("gcd: these are the two operands:\n");
|
||
|
print(stdout, p1);
|
||
|
print(stdout, p2);
|
||
|
#endif
|
||
|
|
||
|
if (equal(p1, p2)) {
|
||
|
push(p1);
|
||
|
return;
|
||
|
}
|
||
|
#if GMP
|
||
|
if (p1->k == QNUM && p2->k == QNUM) {
|
||
|
push(p1);
|
||
|
push(p2);
|
||
|
gcd_numbers();
|
||
|
return;
|
||
|
}
|
||
|
#else
|
||
|
if (p1->k == NUM && p2->k == NUM) {
|
||
|
push(p1);
|
||
|
push(p2);
|
||
|
gcd_numbers();
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
if (car(p1) == symbol(ADD) && car(p2) == symbol(ADD)) {
|
||
|
gcd_expr_expr();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (car(p1) == symbol(ADD)) {
|
||
|
gcd_expr(p1);
|
||
|
p1 = pop();
|
||
|
}
|
||
|
|
||
|
if (car(p2) == symbol(ADD)) {
|
||
|
gcd_expr(p2);
|
||
|
p2 = pop();
|
||
|
}
|
||
|
|
||
|
if (car(p1) == symbol(MULTIPLY) && car(p2) == symbol(MULTIPLY)) {
|
||
|
gcd_term_term();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (car(p1) == symbol(MULTIPLY)) {
|
||
|
gcd_term_factor();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (car(p2) == symbol(MULTIPLY)) {
|
||
|
gcd_factor_term();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// gcd of factors
|
||
|
|
||
|
if (car(p1) == symbol(POWER)) {
|
||
|
p3 = caddr(p1);
|
||
|
p1 = cadr(p1);
|
||
|
} else
|
||
|
p3 = _one;
|
||
|
|
||
|
if (car(p2) == symbol(POWER)) {
|
||
|
p4 = caddr(p2);
|
||
|
p2 = cadr(p2);
|
||
|
} else
|
||
|
p4 = _one;
|
||
|
|
||
|
if (!equal(p1, p2)) {
|
||
|
push(_one);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// are both exponents numerical?
|
||
|
|
||
|
if (isnum(p3) && isnum(p4)) {
|
||
|
push(p1);
|
||
|
if (lessp(p3, p4))
|
||
|
push(p3);
|
||
|
else
|
||
|
push(p4);
|
||
|
power();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// are the exponents multiples of eah other?
|
||
|
|
||
|
push(p3);
|
||
|
push(p4);
|
||
|
divide();
|
||
|
|
||
|
p5 = pop();
|
||
|
|
||
|
if (isnum(p5)) {
|
||
|
|
||
|
push(p1);
|
||
|
|
||
|
// choose the smallest exponent
|
||
|
|
||
|
if (car(p3) == symbol(MULTIPLY) && isnum(cadr(p3)))
|
||
|
p5 = cadr(p3);
|
||
|
else
|
||
|
p5 = _one;
|
||
|
|
||
|
if (car(p4) == symbol(MULTIPLY) && isnum(cadr(p4)))
|
||
|
p6 = cadr(p4);
|
||
|
else
|
||
|
p6 = _one;
|
||
|
|
||
|
if (lessp(p5, p6))
|
||
|
push(p3);
|
||
|
else
|
||
|
push(p4);
|
||
|
|
||
|
power();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
push(p3);
|
||
|
push(p4);
|
||
|
subtract();
|
||
|
|
||
|
p5 = pop();
|
||
|
|
||
|
if (!isnum(p5)) {
|
||
|
push(_one);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// can't be equal because of test near beginning
|
||
|
|
||
|
push(p1);
|
||
|
|
||
|
if (isnegativenumber(p5))
|
||
|
push(p3);
|
||
|
else
|
||
|
push(p4);
|
||
|
|
||
|
power();
|
||
|
}
|
||
|
|
||
|
// in this case gcd is used as a composite function, i.e. gcd(gcd(gcd...
|
||
|
|
||
|
static void
|
||
|
gcd_expr_expr(void)
|
||
|
{
|
||
|
if (length(p1) != length(p2)) {
|
||
|
push(_one);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
p3 = cdr(p1);
|
||
|
push(car(p3));
|
||
|
p3 = cdr(p3);
|
||
|
while (iscons(p3)) {
|
||
|
push(car(p3));
|
||
|
gcd();
|
||
|
p3 = cdr(p3);
|
||
|
}
|
||
|
p3 = pop();
|
||
|
|
||
|
p4 = cdr(p2);
|
||
|
push(car(p4));
|
||
|
p4 = cdr(p4);
|
||
|
while (iscons(p4)) {
|
||
|
push(car(p4));
|
||
|
gcd();
|
||
|
p4 = cdr(p4);
|
||
|
}
|
||
|
p4 = pop();
|
||
|
|
||
|
push(p1);
|
||
|
push(p3);
|
||
|
divide();
|
||
|
p5 = pop();
|
||
|
|
||
|
push(p2);
|
||
|
push(p4);
|
||
|
divide();
|
||
|
p6 = pop();
|
||
|
|
||
|
if (equal(p5, p6)) {
|
||
|
push(p5);
|
||
|
push(p3);
|
||
|
push(p4);
|
||
|
gcd();
|
||
|
multiply();
|
||
|
} else
|
||
|
push(_one);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
gcd_expr(U *p)
|
||
|
{
|
||
|
p = cdr(p);
|
||
|
push(car(p));
|
||
|
p = cdr(p);
|
||
|
while (iscons(p)) {
|
||
|
push(car(p));
|
||
|
gcd();
|
||
|
p = cdr(p);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
gcd_term_term(void)
|
||
|
{
|
||
|
push(_one);
|
||
|
p3 = cdr(p1);
|
||
|
while (iscons(p3)) {
|
||
|
p4 = cdr(p2);
|
||
|
while (iscons(p4)) {
|
||
|
push(car(p3));
|
||
|
push(car(p4));
|
||
|
gcd();
|
||
|
multiply();
|
||
|
p4 = cdr(p4);
|
||
|
}
|
||
|
p3 = cdr(p3);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
gcd_term_factor(void)
|
||
|
{
|
||
|
push(_one);
|
||
|
p3 = cdr(p1);
|
||
|
while (iscons(p3)) {
|
||
|
push(car(p3));
|
||
|
push(p2);
|
||
|
gcd();
|
||
|
multiply();
|
||
|
p3 = cdr(p3);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
gcd_factor_term(void)
|
||
|
{
|
||
|
push(_one);
|
||
|
p4 = cdr(p2);
|
||
|
while (iscons(p4)) {
|
||
|
push(p1);
|
||
|
push(car(p4));
|
||
|
gcd();
|
||
|
multiply();
|
||
|
p4 = cdr(p4);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static char *s[] = {
|
||
|
|
||
|
"gcd(30,42)",
|
||
|
"6",
|
||
|
|
||
|
"gcd(42,30)",
|
||
|
"6",
|
||
|
|
||
|
"gcd(-30,42)",
|
||
|
"6",
|
||
|
|
||
|
"gcd(42,-30)",
|
||
|
"6",
|
||
|
|
||
|
"gcd(30,-42)",
|
||
|
"6",
|
||
|
|
||
|
"gcd(-42,30)",
|
||
|
"6",
|
||
|
|
||
|
"gcd(-30,-42)",
|
||
|
"6",
|
||
|
|
||
|
"gcd(-42,-30)",
|
||
|
"6",
|
||
|
|
||
|
"gcd(x,x)",
|
||
|
"x",
|
||
|
|
||
|
"gcd(-x,x)",
|
||
|
"x",
|
||
|
|
||
|
"gcd(x,-x)",
|
||
|
"x",
|
||
|
|
||
|
"gcd(-x,-x)",
|
||
|
"-x",
|
||
|
|
||
|
"gcd(x^2,x^3)",
|
||
|
"x^2",
|
||
|
|
||
|
"gcd(x,y)",
|
||
|
"1",
|
||
|
|
||
|
"gcd(y,x)",
|
||
|
"1",
|
||
|
|
||
|
"gcd(x*y,y)",
|
||
|
"y",
|
||
|
|
||
|
"gcd(x*y,y^2)",
|
||
|
"y",
|
||
|
|
||
|
"gcd(x^2*y^2,x^3*y^3)",
|
||
|
"x^2*y^2",
|
||
|
|
||
|
"gcd(x^2,x^3)",
|
||
|
"x^2",
|
||
|
|
||
|
// gcd of expr
|
||
|
|
||
|
"gcd(x+y,x+z)",
|
||
|
"1",
|
||
|
|
||
|
"gcd(x+y,x+y)",
|
||
|
"x+y",
|
||
|
|
||
|
"gcd(x+y,2*x+2*y)",
|
||
|
"x+y",
|
||
|
|
||
|
"gcd(-x-y,x+y)",
|
||
|
"x+y",
|
||
|
|
||
|
"gcd(4*x+4*y,6*x+6*y)",
|
||
|
"2*x+2*y",
|
||
|
|
||
|
"gcd(4*x+4*y+4,6*x+6*y+6)",
|
||
|
"2+2*x+2*y",
|
||
|
|
||
|
"gcd(4*x+4*y+4,6*x+6*y+12)",
|
||
|
"1",
|
||
|
|
||
|
"gcd(27*t^3+y^3+9*t*y^2+27*t^2*y,t+y)",
|
||
|
"1",
|
||
|
|
||
|
// gcd expr factor
|
||
|
|
||
|
"gcd(2*a^2*x^2+a*x+a*b,a)",
|
||
|
"a",
|
||
|
|
||
|
"gcd(2*a^2*x^2+a*x+a*b,a^2)",
|
||
|
"a",
|
||
|
|
||
|
"gcd(2*a^2*x^2+2*a*x+2*a*b,a)",
|
||
|
"a",
|
||
|
|
||
|
// gcd expr term
|
||
|
|
||
|
"gcd(2*a^2*x^2+2*a*x+2*a*b,2*a)",
|
||
|
"2*a",
|
||
|
|
||
|
"gcd(2*a^2*x^2+2*a*x+2*a*b,3*a)",
|
||
|
"a",
|
||
|
|
||
|
"gcd(2*a^2*x^2+2*a*x+2*a*b,4*a)",
|
||
|
"2*a",
|
||
|
|
||
|
// gcd factor factor
|
||
|
|
||
|
"gcd(x,x^2)",
|
||
|
"x",
|
||
|
|
||
|
"gcd(x,x^a)",
|
||
|
"1",
|
||
|
};
|
||
|
|
||
|
void
|
||
|
test_gcd(void)
|
||
|
{
|
||
|
test(__FILE__, s, sizeof s / sizeof (char *));
|
||
|
}
|