UNPKG

algebrite

Version:

Computer Algebra System in Coffeescript

384 lines (305 loc) 5.63 kB
### Power function Input: push Base push Exponent Output: Result on stack ### Eval_power = -> push(cadr(p1)) Eval() push(caddr(p1)) Eval() power() power = -> save() yypower() restore() yypower = -> n = 0 p2 = pop() p1 = pop() # both base and exponent are rational numbers? if (isrational(p1) && isrational(p2)) push(p1) push(p2) qpow() return # both base and exponent are either rational or double? if (isnum(p1) && isnum(p2)) push(p1) push(p2) dpow() return if (istensor(p1)) power_tensor() return if (p1 == symbol(E) && car(p2) == symbol(LOG)) push(cadr(p2)) return if (p1 == symbol(E) && isdouble(p2)) push_double(exp(p2.d)) return # 1 ^ a -> 1 # a ^ 0 -> 1 if (equal(p1, one) || iszero(p2)) push(one) return # a ^ 1 -> a if (equal(p2, one)) push(p1) return # (a * b) ^ c -> (a ^ c) * (b ^ c) if (car(p1) == symbol(MULTIPLY)) p1 = cdr(p1) push(car(p1)) push(p2) power() p1 = cdr(p1) while (iscons(p1)) push(car(p1)) push(p2) power() multiply() p1 = cdr(p1) return # (a ^ b) ^ c -> a ^ (b * c) if (car(p1) == symbol(POWER)) push(cadr(p1)) push(caddr(p1)) push(p2) multiply() power() return # (a + b) ^ n -> (a + b) * (a + b) ... if (expanding && isadd(p1) && isnum(p2)) push(p2) n = pop_integer() if (n > 1 && n != 0x80000000) power_sum(n) return # sin(x) ^ 2n -> (1 - cos(x) ^ 2) ^ n if (trigmode == 1 && car(p1) == symbol(SIN) && iseveninteger(p2)) push_integer(1) push(cadr(p1)) cosine() push_integer(2) power() subtract() push(p2) push_rational(1, 2) multiply() power() return # cos(x) ^ 2n -> (1 - sin(x) ^ 2) ^ n if (trigmode == 2 && car(p1) == symbol(COS) && iseveninteger(p2)) push_integer(1) push(cadr(p1)) sine() push_integer(2) power() subtract() push(p2) push_rational(1, 2) multiply() power() return # complex number? (just number, not expression) if (iscomplexnumber(p1)) # integer power? # n will be negative here, positive n already handled if (isinteger(p2)) # / \ n # -n | a - ib | # (a + ib) = | -------- | # | 2 2 | # \ a + b / push(p1) conjugate() p3 = pop() push(p3) push(p3) push(p1) multiply() divide() push(p2) negate() power() return # noninteger or floating power? if (isnum(p2)) push(p1) mag() push(p2) power() push_integer(-1) push(p1) arg() push(p2) multiply() push(symbol(PI)) divide() power() multiply() return ### push(p1) mag() push(p2) power() push(symbol(E)) push(p1) arg() push(p2) multiply() push(imaginaryunit) multiply() power() multiply() ### if (simplify_polar()) return push_symbol(POWER) push(p1) push(p2) list(3) #----------------------------------------------------------------------------- # # Compute the power of a sum # # Input: p1 sum # # n exponent # # Output: Result on stack # # Note: # # Uses the multinomial series (see Math World) # # n n! n1 n2 nk # (a1 + a2 + ... + ak) = sum (--------------- a1 a2 ... ak ) # n1! n2! ... nk! # # The sum is over all n1 ... nk such that n1 + n2 + ... + nk = n. # #----------------------------------------------------------------------------- # first index is the term number 0..k-1, second index is the exponent 0..n #define A(i, j) frame[(i) * (n + 1) + (j)] power_sum = (n) -> a = [] i = 0 j = 0 k = 0 # number of terms in the sum k = length(p1) - 1 # local frame push_frame(k * (n + 1)) # array of powers p1 = cdr(p1) for i in [0...k] for j in [0..n] push(car(p1)) push_integer(j) power() stack[frame + (i) * (n + 1) + (j)] = pop() p1 = cdr(p1) push_integer(n) factorial() p1 = pop() for i in [0...k] a[i] = 0 push(zero) multinomial_sum(k, n, a, 0, n) pop_frame(k * (n + 1)) #----------------------------------------------------------------------------- # # Compute multinomial sum # # Input: k number of factors # # n overall exponent # # a partition array # # i partition array index # # m partition remainder # # p1 n! # # A factor array # # Output: Result on stack # # Note: # # Uses recursive descent to fill the partition array. # #----------------------------------------------------------------------------- #int k, int n, int *a, int i, int m multinomial_sum = (k,n,a,i,m) -> j = 0 if (i < k - 1) for j in [0..m] a[i] = j multinomial_sum(k, n, a, i + 1, m - j) return a[i] = m # coefficient push(p1) for j in [0...k] push_integer(a[j]) factorial() divide() # factors for j in [0...k] push(stack[frame + (j) * (n + 1) + a[j]]) multiply() add() # exp(n/2 i pi) ? # p2 is the exponent expression # clobbers p3 simplify_polar = -> n = 0 n = isquarterturn(p2) switch(n) when 0 doNothing = 1 when 1 push_integer(1) return 1 when 2 push_integer(-1) return 1 when 3 push(imaginaryunit) return 1 when 4 push(imaginaryunit) negate() return 1 if (car(p2) == symbol(ADD)) p3 = cdr(p2) while (iscons(p3)) n = isquarterturn(car(p3)) if (n) break p3 = cdr(p3) switch (n) when 0 return 0 when 1 push_integer(1) when 2 push_integer(-1) when 3 push(imaginaryunit) when 4 push(imaginaryunit) negate() push(p2) push(car(p3)) subtract() exponential() multiply() return 1 return 0