UNPKG

algebrite

Version:

Computer Algebra System in Coffeescript

171 lines (135 loc) 2.47 kB
factorial = -> n = 0 save() p1 = pop() push(p1) n = pop_integer() if (n < 0 || isNaN(n)) push_symbol(FACTORIAL) push(p1) list(2) restore() return bignum_factorial(n) restore() # 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) # this function is not actually used, but # all these simplifications # do happen automatically via simplify simplifyfactorials = -> x = 0 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() sfac_product = -> i = 0 j = 0 n = 0 s = tos p1 = cdr(p1) n = 0 while (iscons(p1)) push(car(p1)) p1 = cdr(p1) n++ for i in [0...(n - 1)] if (stack[s + i] == symbol(NIL)) continue for j in [(i + 1)...n] if (stack[s + j] == symbol(NIL)) continue sfac_product_f(s, i, j) push(one) for i in [0...n] if (stack[s+i] == symbol(NIL)) continue push(stack[s+i]) multiply() p1 = pop() tos -= n push(p1) sfac_product_f = (s,a,b) -> i = 0 n = 0 p1 = stack[s + a] p2 = stack[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 || isNaN(n)) return if (n < 0) n = -n p5 = p1 p1 = p2 p2 = p5 p5 = p3 p3 = p4 p4 = p5 push(one) for i in [1..n] push(cadr(p2)) push_integer(i) add() push(p3) power() multiply() stack[s+a] = pop() stack[s+b] = symbol(NIL)