eigenmath/roots.cpp

304 lines
3.9 KiB
C++

#include "stdafx.h"
#include "defs.h"
extern void sort_stack(int);
void roots(void);
static void roots2(void);
static void roots3(void);
static void mini_solve(void);
#define POLY p1
#define X p2
#define A p3
#define B p4
#define C p5
#define Y p6
void
eval_roots(void)
{
// A == B -> A - B
p2 = cadr(p1);
if (car(p2) == symbol(SETQ) || car(p2) == symbol(TESTEQ)) {
push(cadr(p2));
eval();
push(caddr(p2));
eval();
subtract();
} else {
push(p2);
eval();
p2 = pop();
if (car(p2) == symbol(SETQ) || car(p2) == symbol(TESTEQ)) {
push(cadr(p2));
eval();
push(caddr(p2));
eval();
subtract();
} else
push(p2);
}
// 2nd arg, x
push(caddr(p1));
eval();
p2 = pop();
if (p2 == symbol(NIL))
guess();
else
push(p2);
p2 = pop();
p1 = pop();
if (!ispoly(p1, p2))
stop("roots: 1st argument is not a polynomial");
push(p1);
push(p2);
roots();
}
void
roots(void)
{
int h, i, n;
h = tos - 2;
roots2();
n = tos - h;
if (n == 0)
stop("roots: the polynomial is not factorable, no roots found");
if (n == 1)
return;
sort_stack(n);
save();
p1 = alloc_tensor(n);
p1->u.tensor->ndim = 1;
p1->u.tensor->dim[0] = n;
for (i = 0; i < n; i++)
p1->u.tensor->elem[i] = stack[h + i];
tos = h;
push(p1);
restore();
}
static void
roots2(void)
{
save();
p2 = pop();
p1 = pop();
push(p1);
push(p2);
factorpoly();
p1 = pop();
if (car(p1) == symbol(MULTIPLY)) {
p1 = cdr(p1);
while (iscons(p1)) {
push(car(p1));
push(p2);
roots3();
p1 = cdr(p1);
}
} else {
push(p1);
push(p2);
roots3();
}
restore();
}
static void
roots3(void)
{
save();
p2 = pop();
p1 = pop();
if (car(p1) == symbol(POWER) && ispoly(cadr(p1), p2) && isposint(caddr(p1))) {
push(cadr(p1));
push(p2);
mini_solve();
} else if (ispoly(p1, p2)) {
push(p1);
push(p2);
mini_solve();
}
restore();
}
//-----------------------------------------------------------------------------
//
// Input: stack[tos - 2] polynomial
//
// stack[tos - 1] dependent symbol
//
// Output: stack roots on stack
//
// (input args are popped first)
//
//-----------------------------------------------------------------------------
static void
mini_solve(void)
{
int n;
save();
X = pop();
POLY = pop();
push(POLY);
push(X);
n = coeff();
// AX + B, X = -B/A
if (n == 2) {
A = pop();
B = pop();
push(B);
push(A);
divide();
negate();
restore();
return;
}
// AX^2 + BX + C, X = (-B +/- (B^2 - 4AC)^(1/2)) / (2A)
if (n == 3) {
A = pop();
B = pop();
C = pop();
push(B);
push(B);
multiply();
push_integer(4);
push(A);
multiply();
push(C);
multiply();
subtract();
push_rational(1, 2);
power();
Y = pop();
push(Y); // 1st root
push(B);
subtract();
push(A);
divide();
push_rational(1, 2);
multiply();
push(Y); // 2nd root
push(B);
add();
negate();
push(A);
divide();
push_rational(1, 2);
multiply();
restore();
return;
}
tos -= n;
restore();
}
#if SELFTEST
static char *s[] = {
"roots(x)",
"0",
"roots(x^2)",
"0",
"roots(x^3)",
"0",
"roots(2 x)",
"0",
"roots(2 x^2)",
"0",
"roots(2 x^3)",
"0",
"roots(6+11*x+6*x^2+x^3)",
"(-3,-2,-1)",
"roots(a*x^2+b*x+c)",
"(-b/(2*a)-(-4*a*c+b^2)^(1/2)/(2*a),-b/(2*a)+(-4*a*c+b^2)^(1/2)/(2*a))",
"roots(3+7*x+5*x^2+x^3)",
"(-3,-1)",
"roots(x^3+x^2+x+1)",
"(-1,-i,i)",
"roots(x^4+1)",
"Stop: roots: the polynomial is not factorable, no roots found",
// "roots(0)",
// "roots: Sorry, the argument is not factorable over integers, no roots found.",
"roots(x^2==1)",
"(-1,1)",
"roots(3 x + 12 == 24)",
"4",
"roots(3/x + 12 = 24)",
"1/4",
"y=roots(x^2+b*x+c/k)[1]",
"",
"y^2+b*y+c/k",
"0",
"y=roots(x^2+b*x+c/k)[2]",
"",
"y^2+b*y+c/k",
"0",
"y=roots(a*x^2+b*x+c/4)[1]",
"",
"a*y^2+b*y+c/4",
"0",
"y=roots(a*x^2+b*x+c/4)[2]",
"",
"a*y^2+b*y+c/4",
"0",
"y=quote(y)",
"",
};
void
test_roots(void)
{
test(__FILE__, s, sizeof s / sizeof (char *));
}
#endif