UNPKG

algebrite

Version:

Computer Algebra System in Coffeescript

171 lines (147 loc) 3.34 kB
# Sine function of numerical and symbolic arguments Eval_sin = -> #console.log "sin ---- " push(cadr(p1)) Eval() sine() #console.log "sin end ---- " sine = -> #console.log "sine ---- " save() p1 = pop() if (car(p1) == symbol(ADD)) # sin of a sum can be further decomposed into #sin(alpha+beta) = sin(alpha)*cos(beta)+sin(beta)*cos(alpha) sine_of_angle_sum() else sine_of_angle() restore() #console.log "sine end ---- " # Use angle sum formula for special angles. #define A p3 #define B p4 # decompose sum sin(alpha+beta) into # sin(alpha)*cos(beta)+sin(beta)*cos(alpha) sine_of_angle_sum = -> #console.log "sin of angle sum ---- " p2 = cdr(p1) while (iscons(p2)) p4 = car(p2); # p4 is B if (isnpi(p4)) # p4 is B push(p1) push(p4); # p4 is B subtract() p3 = pop(); # p3 is A push(p3); # p3 is A sine() push(p4); # p4 is B cosine() multiply() push(p3); # p3 is A cosine() push(p4); # p4 is B sine() multiply() add() #console.log "sin of angle sum end ---- " return p2 = cdr(p2) sine_of_angle() #console.log "sin of angle sum end ---- " sine_of_angle = -> if (car(p1) == symbol(ARCSIN)) push(cadr(p1)) return if isdouble(p1) d = Math.sin(p1.d) if (Math.abs(d) < 1e-10) d = 0.0 push_double(d) return # sine function is antisymmetric, sin(-x) = -sin(x) if (isnegative(p1)) push(p1) negate() sine() negate() return # sin(arctan(x)) = x / sqrt(1 + x^2) # see p. 173 of the CRC Handbook of Mathematical Sciences if (car(p1) == symbol(ARCTAN)) push(cadr(p1)) push_integer(1) push(cadr(p1)) push_integer(2) power() add() push_rational(-1, 2) power() multiply() return # multiply by 180/pi to go from radians to degrees. # we go from radians to degrees because it's much # easier to calculate symbolic results of most (not all) "classic" # angles (e.g. 30,45,60...) if we calculate the degrees # and the we do a switch on that. # Alternatively, we could look at the fraction of pi # (e.g. 60 degrees is 1/3 pi) but that's more # convoluted as we'd need to look at both numerator and # denominator. push(p1) push_integer(180) multiply() if evaluatingAsFloats push_double(Math.PI) else push_symbol(PI) divide() n = pop_integer() # most "good" (i.e. compact) trigonometric results # happen for a round number of degrees. There are some exceptions # though, e.g. 22.5 degrees, which we don't capture here. if (n < 0 || isNaN(n)) push(symbol(SIN)) push(p1) list(2) return # values of some famous angles. Many more here: # https://en.wikipedia.org/wiki/Trigonometric_constants_expressed_in_real_radicals switch (n % 360) when 0, 180 push_integer(0) when 30, 150 push_rational(1, 2) when 210, 330 push_rational(-1, 2) when 45, 135 push_rational(1, 2) push_integer(2) push_rational(1, 2) power() multiply() when 225, 315 push_rational(-1, 2) push_integer(2) push_rational(1, 2) power() multiply() when 60, 120 push_rational(1, 2) push_integer(3) push_rational(1, 2) power() multiply() when 240, 300 push_rational(-1, 2) push_integer(3) push_rational(1, 2) power() multiply() when 90 push_integer(1) when 270 push_integer(-1) else push(symbol(SIN)) push(p1) list(2)