UNPKG

3.34 kBtext/coffeescriptView Raw
1# Sine function of numerical and symbolic arguments
2
3
4
5Eval_sin = ->
6 #console.log "sin ---- "
7 push(cadr(p1))
8 Eval()
9 sine()
10 #console.log "sin end ---- "
11
12sine = ->
13 #console.log "sine ---- "
14 save()
15 p1 = pop()
16 if (car(p1) == symbol(ADD))
17 # sin of a sum can be further decomposed into
18 #sin(alpha+beta) = sin(alpha)*cos(beta)+sin(beta)*cos(alpha)
19 sine_of_angle_sum()
20 else
21 sine_of_angle()
22 restore()
23 #console.log "sine end ---- "
24
25# Use angle sum formula for special angles.
26
27#define A p3
28#define B p4
29
30# decompose sum sin(alpha+beta) into
31# sin(alpha)*cos(beta)+sin(beta)*cos(alpha)
32sine_of_angle_sum = ->
33 #console.log "sin of angle sum ---- "
34 p2 = cdr(p1)
35 while (iscons(p2))
36 p4 = car(p2); # p4 is B
37 if (isnpi(p4)) # p4 is B
38 push(p1)
39 push(p4); # p4 is B
40 subtract()
41 p3 = pop(); # p3 is A
42 push(p3); # p3 is A
43 sine()
44 push(p4); # p4 is B
45 cosine()
46 multiply()
47 push(p3); # p3 is A
48 cosine()
49 push(p4); # p4 is B
50 sine()
51 multiply()
52 add()
53 #console.log "sin of angle sum end ---- "
54 return
55 p2 = cdr(p2)
56 sine_of_angle()
57 #console.log "sin of angle sum end ---- "
58
59sine_of_angle = ->
60
61 if (car(p1) == symbol(ARCSIN))
62 push(cadr(p1))
63 return
64
65 if isdouble(p1)
66 d = Math.sin(p1.d)
67 if (Math.abs(d) < 1e-10)
68 d = 0.0
69 push_double(d)
70 return
71
72 # sine function is antisymmetric, sin(-x) = -sin(x)
73
74 if (isnegative(p1))
75 push(p1)
76 negate()
77 sine()
78 negate()
79 return
80
81 # sin(arctan(x)) = x / sqrt(1 + x^2)
82
83 # see p. 173 of the CRC Handbook of Mathematical Sciences
84
85 if (car(p1) == symbol(ARCTAN))
86 push(cadr(p1))
87 push_integer(1)
88 push(cadr(p1))
89 push_integer(2)
90 power()
91 add()
92 push_rational(-1, 2)
93 power()
94 multiply()
95 return
96
97 # multiply by 180/pi to go from radians to degrees.
98 # we go from radians to degrees because it's much
99 # easier to calculate symbolic results of most (not all) "classic"
100 # angles (e.g. 30,45,60...) if we calculate the degrees
101 # and the we do a switch on that.
102 # Alternatively, we could look at the fraction of pi
103 # (e.g. 60 degrees is 1/3 pi) but that's more
104 # convoluted as we'd need to look at both numerator and
105 # denominator.
106
107 push(p1)
108 push_integer(180)
109 multiply()
110 if evaluatingAsFloats
111 push_double(Math.PI)
112 else
113 push_symbol(PI)
114 divide()
115
116 n = pop_integer()
117
118 # most "good" (i.e. compact) trigonometric results
119 # happen for a round number of degrees. There are some exceptions
120 # though, e.g. 22.5 degrees, which we don't capture here.
121 if (n < 0 || isNaN(n))
122 push(symbol(SIN))
123 push(p1)
124 list(2)
125 return
126
127 # values of some famous angles. Many more here:
128 # https://en.wikipedia.org/wiki/Trigonometric_constants_expressed_in_real_radicals
129
130 switch (n % 360)
131 when 0, 180
132 push_integer(0)
133 when 30, 150
134 push_rational(1, 2)
135 when 210, 330
136 push_rational(-1, 2)
137 when 45, 135
138 push_rational(1, 2)
139 push_integer(2)
140 push_rational(1, 2)
141 power()
142 multiply()
143 when 225, 315
144 push_rational(-1, 2)
145 push_integer(2)
146 push_rational(1, 2)
147 power()
148 multiply()
149 when 60, 120
150 push_rational(1, 2)
151 push_integer(3)
152 push_rational(1, 2)
153 power()
154 multiply()
155 when 240, 300
156 push_rational(-1, 2)
157 push_integer(3)
158 push_rational(1, 2)
159 power()
160 multiply()
161 when 90
162 push_integer(1)
163 when 270
164 push_integer(-1)
165 else
166 push(symbol(SIN))
167 push(p1)
168 list(2)
169
170