123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- #include "stdafx.h"
- #include "defs.h"
- extern void bignum_factorial(int);
- void
- factorial(void)
- {
- int n;
- save();
- p1 = pop();
- push(p1);
- n = pop_integer();
- if (n < 0 || n == (int) 0x80000000) {
- push_symbol(FACTORIAL);
- push(p1);
- list(2);
- restore();
- return;
- }
- bignum_factorial(n);
- restore();
- }
- void sfac_product(void);
- void sfac_product_f(U **, int, int);
- // simplification rules for factorials (m < n)
- //
- // (e + 1) * factorial(e) -> factorial(e + 1)
- //
- // factorial(e) / e -> factorial(e - 1)
- //
- // e / factorial(e) -> 1 / factorial(e - 1)
- //
- // factorial(e + n)
- // ---------------- -> (e + m + 1)(e + m + 2)...(e + n)
- // factorial(e + m)
- //
- // factorial(e + m) 1
- // ---------------- -> --------------------------------
- // factorial(e + n) (e + m + 1)(e + m + 2)...(e + n)
- void
- simplifyfactorials(void)
- {
- int x;
- save();
- x = expanding;
- expanding = 0;
- p1 = pop();
- if (car(p1) == symbol(ADD)) {
- push(zero);
- p1 = cdr(p1);
- while (iscons(p1)) {
- push(car(p1));
- simplifyfactorials();
- add();
- p1 = cdr(p1);
- }
- expanding = x;
- restore();
- return;
- }
- if (car(p1) == symbol(MULTIPLY)) {
- sfac_product();
- expanding = x;
- restore();
- return;
- }
- push(p1);
- expanding = x;
- restore();
- }
- void
- sfac_product(void)
- {
- int i, j, n;
- U **s;
- s = stack + tos;
- p1 = cdr(p1);
- n = 0;
- while (iscons(p1)) {
- push(car(p1));
- p1 = cdr(p1);
- n++;
- }
- for (i = 0; i < n - 1; i++) {
- if (s[i] == symbol(NIL))
- continue;
- for (j = i + 1; j < n; j++) {
- if (s[j] == symbol(NIL))
- continue;
- sfac_product_f(s, i, j);
- }
- }
- push(one);
- for (i = 0; i < n; i++) {
- if (s[i] == symbol(NIL))
- continue;
- push(s[i]);
- multiply();
- }
- p1 = pop();
- tos -= n;
- push(p1);
- }
- void
- sfac_product_f(U **s, int a, int b)
- {
- int i, n;
- p1 = s[a];
- p2 = s[b];
- if (ispower(p1)) {
- p3 = caddr(p1);
- p1 = cadr(p1);
- } else
- p3 = one;
- if (ispower(p2)) {
- p4 = caddr(p2);
- p2 = cadr(p2);
- } else
- p4 = one;
- if (isfactorial(p1) && isfactorial(p2)) {
- // Determine if the powers cancel.
- push(p3);
- push(p4);
- add();
- yyexpand();
- n = pop_integer();
- if (n != 0)
- return;
- // Find the difference between the two factorial args.
- // For example, the difference between (a + 2)! and a! is 2.
- push(cadr(p1));
- push(cadr(p2));
- subtract();
- yyexpand(); // to simplify
- n = pop_integer();
- if (n == 0 || n == (int) 0x80000000)
- return;
- if (n < 0) {
- n = -n;
- p5 = p1;
- p1 = p2;
- p2 = p5;
- p5 = p3;
- p3 = p4;
- p4 = p5;
- }
- push(one);
- for (i = 1; i <= n; i++) {
- push(cadr(p2));
- push_integer(i);
- add();
- push(p3);
- power();
- multiply();
- }
- s[a] = pop();
- s[b] = symbol(NIL);
- }
- }
|