175 lines
2.2 KiB
C++
175 lines
2.2 KiB
C++
|
#include "stdafx.h"
|
||
|
#include "defs.h"
|
||
|
#define DEBUG 0
|
||
|
static void __rationalize_tensor(void);
|
||
|
static void multiply_denominators(U *);
|
||
|
static void multiply_denominators_term(U *);
|
||
|
static void multiply_denominators_factor(U *);
|
||
|
static void __lcm(void);
|
||
|
|
||
|
void
|
||
|
eval_rationalize(void)
|
||
|
{
|
||
|
push(cadr(p1));
|
||
|
eval();
|
||
|
rationalize();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
rationalize(void)
|
||
|
{
|
||
|
int x = expanding;
|
||
|
save();
|
||
|
yyrationalize();
|
||
|
restore();
|
||
|
expanding = x;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
yyrationalize(void)
|
||
|
{
|
||
|
p1 = pop();
|
||
|
|
||
|
if (istensor(p1)) {
|
||
|
__rationalize_tensor();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
expanding = 0;
|
||
|
|
||
|
if (car(p1) != symbol(ADD)) {
|
||
|
push(p1);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// get common denominator
|
||
|
|
||
|
push(one);
|
||
|
multiply_denominators(p1);
|
||
|
p2 = pop();
|
||
|
|
||
|
// multiply each term by common denominator
|
||
|
|
||
|
push(zero);
|
||
|
p3 = cdr(p1);
|
||
|
while (iscons(p3)) {
|
||
|
push(p2);
|
||
|
push(car(p3));
|
||
|
multiply();
|
||
|
add();
|
||
|
p3 = cdr(p3);
|
||
|
}
|
||
|
|
||
|
// collect common factors
|
||
|
|
||
|
Condense();
|
||
|
|
||
|
// divide by common denominator
|
||
|
|
||
|
push(p2);
|
||
|
divide();
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
multiply_denominators(U *p)
|
||
|
{
|
||
|
if (car(p) == symbol(ADD)) {
|
||
|
p = cdr(p);
|
||
|
while (iscons(p)) {
|
||
|
multiply_denominators_term(car(p));
|
||
|
p = cdr(p);
|
||
|
}
|
||
|
} else
|
||
|
multiply_denominators_term(p);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
multiply_denominators_term(U *p)
|
||
|
{
|
||
|
if (car(p) == symbol(MULTIPLY)) {
|
||
|
p = cdr(p);
|
||
|
while (iscons(p)) {
|
||
|
multiply_denominators_factor(car(p));
|
||
|
p = cdr(p);
|
||
|
}
|
||
|
} else
|
||
|
multiply_denominators_factor(p);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
multiply_denominators_factor(U *p)
|
||
|
{
|
||
|
if (car(p) != symbol(POWER))
|
||
|
return;
|
||
|
|
||
|
push(p);
|
||
|
|
||
|
p = caddr(p);
|
||
|
|
||
|
// like x^(-2) ?
|
||
|
|
||
|
if (isnegativenumber(p)) {
|
||
|
inverse();
|
||
|
__lcm();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// like x^(-a) ?
|
||
|
|
||
|
if (car(p) == symbol(MULTIPLY) && isnegativenumber(cadr(p))) {
|
||
|
inverse();
|
||
|
__lcm();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// no match
|
||
|
|
||
|
pop();
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
__rationalize_tensor(void)
|
||
|
{
|
||
|
int i, n;
|
||
|
|
||
|
push(p1);
|
||
|
|
||
|
eval(); // makes a copy
|
||
|
|
||
|
p1 = pop();
|
||
|
|
||
|
if (!istensor(p1)) { // might be zero
|
||
|
push(p1);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
n = p1->u.tensor->nelem;
|
||
|
|
||
|
for (i = 0; i < n; i++) {
|
||
|
push(p1->u.tensor->elem[i]);
|
||
|
rationalize();
|
||
|
p1->u.tensor->elem[i] = pop();
|
||
|
}
|
||
|
|
||
|
push(p1);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
__lcm(void)
|
||
|
{
|
||
|
save();
|
||
|
|
||
|
p1 = pop();
|
||
|
p2 = pop();
|
||
|
|
||
|
push(p1);
|
||
|
push(p2);
|
||
|
multiply();
|
||
|
push(p1);
|
||
|
push(p2);
|
||
|
gcd();
|
||
|
divide();
|
||
|
|
||
|
restore();
|
||
|
}
|