269 lines
4.1 KiB
C++
269 lines
4.1 KiB
C++
/* Simplify factorials
|
|
|
|
The following script
|
|
|
|
F(n,k) = k binomial(n,k)
|
|
(F(n,k) + F(n,k-1)) / F(n+1,k)
|
|
|
|
generates
|
|
|
|
k! n! n! (1 - k + n)! k! n!
|
|
-------------------- + -------------------- - ----------------------
|
|
(-1 + k)! (1 + n)! (1 + n)! (-k + n)! k (-1 + k)! (1 + n)!
|
|
|
|
Simplify each term to get
|
|
|
|
k 1 - k + n 1
|
|
------- + ----------- - -------
|
|
1 + n 1 + n 1 + n
|
|
|
|
Then simplify the sum to get
|
|
|
|
n
|
|
-------
|
|
1 + n
|
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "defs.h"
|
|
void simfac(void);
|
|
static void simfac_term(void);
|
|
static int yysimfac(int);
|
|
|
|
// simplify factorials term-by-term
|
|
|
|
void
|
|
eval_simfac(void)
|
|
{
|
|
push(cadr(p1));
|
|
eval();
|
|
simfac();
|
|
}
|
|
|
|
#if 1
|
|
|
|
void
|
|
simfac(void)
|
|
{
|
|
int h;
|
|
save();
|
|
p1 = pop();
|
|
if (car(p1) == symbol(ADD)) {
|
|
h = tos;
|
|
p1 = cdr(p1);
|
|
while (p1 != symbol(NIL)) {
|
|
push(car(p1));
|
|
simfac_term();
|
|
p1 = cdr(p1);
|
|
}
|
|
add_all(tos - h);
|
|
} else {
|
|
push(p1);
|
|
simfac_term();
|
|
}
|
|
restore();
|
|
}
|
|
|
|
#else
|
|
|
|
void
|
|
simfac(void)
|
|
{
|
|
int h;
|
|
save();
|
|
p1 = pop();
|
|
if (car(p1) == symbol(ADD)) {
|
|
h = tos;
|
|
p1 = cdr(p1);
|
|
while (p1 != symbol(NIL)) {
|
|
push(car(p1));
|
|
simfac_term();
|
|
p1 = cdr(p1);
|
|
}
|
|
addk(tos - h);
|
|
p1 = pop();
|
|
if (find(p1, symbol(FACTORIAL))) {
|
|
push(p1);
|
|
if (car(p1) == symbol(ADD)) {
|
|
Condense();
|
|
simfac_term();
|
|
}
|
|
}
|
|
} else {
|
|
push(p1);
|
|
simfac_term();
|
|
}
|
|
restore();
|
|
}
|
|
|
|
#endif
|
|
|
|
static void
|
|
simfac_term(void)
|
|
{
|
|
int h;
|
|
|
|
save();
|
|
|
|
p1 = pop();
|
|
|
|
// if not a product of factors then done
|
|
|
|
if (car(p1) != symbol(MULTIPLY)) {
|
|
push(p1);
|
|
restore();
|
|
return;
|
|
}
|
|
|
|
// push all factors
|
|
|
|
h = tos;
|
|
p1 = cdr(p1);
|
|
while (p1 != symbol(NIL)) {
|
|
push(car(p1));
|
|
p1 = cdr(p1);
|
|
}
|
|
|
|
// keep trying until no more to do
|
|
|
|
while (yysimfac(h))
|
|
;
|
|
|
|
multiply_all_noexpand(tos - h);
|
|
|
|
restore();
|
|
}
|
|
|
|
// try all pairs of factors
|
|
|
|
static int
|
|
yysimfac(int h)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = h; i < tos; i++) {
|
|
p1 = stack[i];
|
|
for (j = h; j < tos; j++) {
|
|
if (i == j)
|
|
continue;
|
|
p2 = stack[j];
|
|
|
|
// n! / n -> (n - 1)!
|
|
|
|
if (car(p1) == symbol(FACTORIAL)
|
|
&& car(p2) == symbol(POWER)
|
|
&& isminusone(caddr(p2))
|
|
&& equal(cadr(p1), cadr(p2))) {
|
|
push(cadr(p1));
|
|
push(one);
|
|
subtract();
|
|
factorial();
|
|
stack[i] = pop();
|
|
stack[j] = one;
|
|
return 1;
|
|
}
|
|
|
|
// n / n! -> 1 / (n - 1)!
|
|
|
|
if (car(p2) == symbol(POWER)
|
|
&& isminusone(caddr(p2))
|
|
&& caadr(p2) == symbol(FACTORIAL)
|
|
&& equal(p1, cadadr(p2))) {
|
|
push(p1);
|
|
push_integer(-1);
|
|
add();
|
|
factorial();
|
|
reciprocate();
|
|
stack[i] = pop();
|
|
stack[j] = one;
|
|
return 1;
|
|
}
|
|
|
|
// (n + 1) n! -> (n + 1)!
|
|
|
|
if (car(p2) == symbol(FACTORIAL)) {
|
|
push(p1);
|
|
push(cadr(p2));
|
|
subtract();
|
|
p3 = pop();
|
|
if (isplusone(p3)) {
|
|
push(p1);
|
|
factorial();
|
|
stack[i] = pop();
|
|
stack[j] = one;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// 1 / ((n + 1) n!) -> 1 / (n + 1)!
|
|
|
|
if (car(p1) == symbol(POWER)
|
|
&& isminusone(caddr(p1))
|
|
&& car(p2) == symbol(POWER)
|
|
&& isminusone(caddr(p2))
|
|
&& caadr(p2) == symbol(FACTORIAL)) {
|
|
push(cadr(p1));
|
|
push(cadr(cadr(p2)));
|
|
subtract();
|
|
p3 = pop();
|
|
if (isplusone(p3)) {
|
|
push(cadr(p1));
|
|
factorial();
|
|
reciprocate();
|
|
stack[i] = pop();
|
|
stack[j] = one;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// (n + 1)! / n! -> n + 1
|
|
|
|
// n! / (n + 1)! -> 1 / (n + 1)
|
|
|
|
if (car(p1) == symbol(FACTORIAL)
|
|
&& car(p2) == symbol(POWER)
|
|
&& isminusone(caddr(p2))
|
|
&& caadr(p2) == symbol(FACTORIAL)) {
|
|
push(cadr(p1));
|
|
push(cadr(cadr(p2)));
|
|
subtract();
|
|
p3 = pop();
|
|
if (isplusone(p3)) {
|
|
stack[i] = cadr(p1);
|
|
stack[j] = one;
|
|
return 1;
|
|
}
|
|
if (isminusone(p3)) {
|
|
push(cadr(cadr(p2)));
|
|
reciprocate();
|
|
stack[i] = pop();
|
|
stack[j] = one;
|
|
return 1;
|
|
}
|
|
if (equaln(p3, 2)) {
|
|
stack[i] = cadr(p1);
|
|
push(cadr(p1));
|
|
push_integer(-1);
|
|
add();
|
|
stack[j] = pop();
|
|
return 1;
|
|
}
|
|
if (equaln(p3, -2)) {
|
|
push(cadr(cadr(p2)));
|
|
reciprocate();
|
|
stack[i] = pop();
|
|
push(cadr(cadr(p2)));
|
|
push_integer(-1);
|
|
add();
|
|
reciprocate();
|
|
stack[j] = pop();
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|