123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- /* 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;
- }
|