UNPKG

algebrite

Version:

Computer Algebra System in Coffeescript

167 lines (140 loc) 2.93 kB
### cos ===================================================================== Tags ---- scripting, JS, internal, treenode, general concept Parameters ---------- x General description ------------------- Returns the cosine of x. ### Eval_cos = -> push(cadr(p1)) Eval() cosine() cosine = -> save() p1 = pop() if (car(p1) == symbol(ADD)) cosine_of_angle_sum() else cosine_of_angle() restore() # Use angle sum formula for special angles. #define A p3 #define B p4 cosine_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 cosine() push(p4); # p4 is B cosine() multiply() push(p3); # p3 is A sine() push(p4); # p4 is B sine() multiply() subtract() return p2 = cdr(p2) cosine_of_angle() cosine_of_angle = -> if (car(p1) == symbol(ARCCOS)) push(cadr(p1)) return if (isdouble(p1)) d = Math.cos(p1.d) if (Math.abs(d) < 1e-10) d = 0.0 push_double(d) return # cosine function is symmetric, cos(-x) = cos(x) if (isnegative(p1)) push(p1) negate() p1 = pop() # cos(arctan(x)) = 1 / sqrt(1 + x^2) # see p. 173 of the CRC Handbook of Mathematical Sciences if (car(p1) == symbol(ARCTAN)) push_integer(1) push(cadr(p1)) push_integer(2) power() add() push_rational(-1, 2) power() 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(COS)) push(p1) list(2) return switch (n % 360) when 90, 270 push_integer(0) when 60, 300 push_rational(1, 2) when 120, 240 push_rational(-1, 2) when 45, 315 push_rational(1, 2) push_integer(2) push_rational(1, 2) power() multiply() when 135, 225 push_rational(-1, 2) push_integer(2) push_rational(1, 2) power() multiply() when 30, 330 push_rational(1, 2) push_integer(3) push_rational(1, 2) power() multiply() when 150, 210 push_rational(-1, 2) push_integer(3) push_rational(1, 2) power() multiply() when 0 push_integer(1) when 180 push_integer(-1) else push(symbol(COS)) push(p1) list(2)