algebrite
Version:
Computer Algebra System in Coffeescript
171 lines (135 loc) • 2.47 kB
text/coffeescript
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)