UNPKG

6.76 kBtext/coffeescriptView Raw
1#(docs are generated from top-level comments, keep an eye on the formatting!)
2
3### abs =====================================================================
4
5Tags
6----
7scripting, JS, internal, treenode, general concept
8
9Parameters
10----------
11x
12
13General description
14-------------------
15Returns the absolute value of a real number, the magnitude of a complex number, or the vector length.
16
17###
18
19###
20 Absolute value of a number,or magnitude of complex z, or norm of a vector
21
22 z abs(z)
23 - ------
24
25 a a
26
27 -a a
28
29 (-1)^a 1
30
31 exp(a + i b) exp(a)
32
33 a b abs(a) abs(b)
34
35 a + i b sqrt(a^2 + b^2)
36
37Notes
38
39 1. Handles mixed polar and rectangular forms, e.g. 1 + exp(i pi/3)
40
41 2. jean-francois.debroux reports that when z=(a+i*b)/(c+i*d) then
42
43 abs(numerator(z)) / abs(denominator(z))
44
45 must be used to get the correct answer. Now the operation is
46 automatic.
47###
48
49
50DEBUG_ABS = false
51
52Eval_abs = ->
53 push(cadr(p1))
54 Eval()
55 abs()
56
57absValFloat = ->
58 Eval()
59 absval()
60 Eval(); # normalize
61 zzfloat()
62 # zzfloat of an abs doesn't necessarily result in a double
63 # , for example if there are variables. But
64 # in many of the tests there should be indeed
65 # a float, these two lines come handy to highlight
66 # when that doesn't happen for those tests.
67 #if !isdouble(stack[tos-1])
68 # stop("absValFloat should return a double and instead got: " + stack[tos-1])
69
70abs = ->
71 save()
72 p1 = pop()
73 push(p1)
74 numerator()
75 absval()
76 push(p1)
77 denominator()
78 absval()
79 divide()
80 restore()
81
82absval = ->
83 save()
84 p1 = pop()
85 input = p1
86
87 if DEBUG_ABS then console.log "ABS of " + p1
88
89
90 # handle all the "number" cases first -----------------------------------------
91 if (iszero(p1))
92 if DEBUG_ABS then console.log " abs: " + p1 + " just zero"
93 push(zero)
94 if DEBUG_ABS then console.log " --> ABS of " + input + " : " + stack[tos-1]
95 restore()
96 return
97
98 if (isnegativenumber(p1))
99 if DEBUG_ABS then console.log " abs: " + p1 + " just a negative"
100 push(p1)
101 negate()
102 restore()
103 return
104
105 if (ispositivenumber(p1))
106 if DEBUG_ABS then console.log " abs: " + p1 + " just a positive"
107 push(p1)
108 if DEBUG_ABS then console.log " --> ABS of " + input + " : " + stack[tos-1]
109 restore()
110 return
111
112 if (p1 == symbol(PI))
113 if DEBUG_ABS then console.log " abs: " + p1 + " of PI"
114 push(p1)
115 if DEBUG_ABS then console.log " --> ABS of " + input + " : " + stack[tos-1]
116 restore()
117 return
118
119 # ??? should there be a shortcut case here for the imaginary unit?
120
121 # now handle decomposition cases ----------------------------------------------
122
123 # we catch the "add", "power", "multiply" cases first,
124 # before falling back to the
125 # negative/positive cases because there are some
126 # simplification thay we might be able to do.
127 # Note that for this routine to give a correct result, this
128 # must be a sum where a complex number appears.
129 # If we apply this to "a+b", we get an incorrect result.
130 if (car(p1) == symbol(ADD) and (
131 findPossibleClockForm(p1) or
132 findPossibleExponentialForm(p1) or
133 Find(p1,imaginaryunit))
134 )
135 if DEBUG_ABS then console.log " abs: " + p1 + " is a sum"
136 if DEBUG_ABS then console.log "abs of a sum"
137 # sum
138 push(p1)
139 rect() # convert polar terms, if any
140 p1 = pop()
141 push(p1)
142 real()
143 push_integer(2)
144 power()
145 push(p1)
146 imag()
147 push_integer(2)
148 power()
149 add()
150 push_rational(1, 2)
151 power()
152 simplify_trig()
153 if DEBUG_ABS then console.log " --> ABS of " + input + " : " + stack[tos-1]
154 restore()
155 return
156
157 if (car(p1) == symbol(POWER) && equaln(cadr(p1), -1))
158 if DEBUG_ABS then console.log " abs: " + p1 + " is -1 to any power"
159 # -1 to any power
160 if evaluatingAsFloats
161 if DEBUG_ABS then console.log " abs: numeric, so result is 1.0"
162 push_double(1.0)
163 else
164 if DEBUG_ABS then console.log " abs: symbolic, so result is 1"
165 push_integer(1)
166 if DEBUG_ABS then console.log " --> ABS of " + input + " : " + stack[tos-1]
167 restore()
168 return
169
170 # abs(a^b) is equal to abs(a)^b IF b is positive
171 if (car(p1) == symbol(POWER) && ispositivenumber(caddr(p1)))
172 if DEBUG_ABS then console.log " abs: " + p1 + " is something to the power of a positive number"
173 push cadr(p1)
174 abs()
175 push caddr(p1)
176 power()
177 if DEBUG_ABS then console.log " --> ABS of " + input + " : " + stack[tos-1]
178 restore()
179 return
180
181 # abs(e^something)
182 if (car(p1) == symbol(POWER) && cadr(p1) == symbol(E))
183 if DEBUG_ABS then console.log " abs: " + p1 + " is an exponential"
184 # exponential
185 push(caddr(p1))
186 real()
187 exponential()
188 if DEBUG_ABS then console.log " --> ABS of " + input + " : " + stack[tos-1]
189 restore()
190 return
191
192 if (car(p1) == symbol(MULTIPLY))
193 if DEBUG_ABS then console.log " abs: " + p1 + " is a product"
194 # product
195 push_integer(1)
196 p1 = cdr(p1)
197 while (iscons(p1))
198 push(car(p1))
199 abs()
200 multiply()
201 p1 = cdr(p1)
202 if DEBUG_ABS then console.log " --> ABS of " + input + " : " + stack[tos-1]
203 restore()
204 return
205
206 if (car(p1) == symbol(ABS))
207 if DEBUG_ABS then console.log " abs: " + p1 + " is abs of a abs"
208 # abs of a abs
209 push_symbol(ABS)
210 push cadr(p1)
211 list(2)
212 if DEBUG_ABS then console.log " --> ABS of " + input + " : " + stack[tos-1]
213 restore()
214 return
215
216 ###
217 # Evaluation via zzfloat()
218 # ...while this is in theory a powerful mechanism, I've commented it
219 # out because I've refined this method enough to not need this.
220 # Evaling via zzfloat() is in principle more problematic because it could
221 # require further evaluations which could end up in further "abs" which
222 # would end up in infinite loops. Better not use it if not necessary.
223
224 # we look directly at the float evaluation of the argument
225 # to see if we end up with a number, which would mean that there
226 # is no imaginary component and we can just return the input
227 # (or its negation) as the result.
228 push p1
229 zzfloat()
230 floatEvaluation = pop()
231
232 if (isnegativenumber(floatEvaluation))
233 if DEBUG_ABS then console.log " abs: " + p1 + " just a negative"
234 push(p1)
235 negate()
236 restore()
237 return
238
239 if (ispositivenumber(floatEvaluation))
240 if DEBUG_ABS then console.log " abs: " + p1 + " just a positive"
241 push(p1)
242 if DEBUG_ABS then console.log " --> ABS of " + input + " : " + stack[tos-1]
243 restore()
244 return
245 ###
246
247 if (istensor(p1))
248 absval_tensor()
249 restore()
250 return
251
252 if (isnegativeterm(p1) || (car(p1) == symbol(ADD) && isnegativeterm(cadr(p1))))
253 push(p1)
254 negate()
255 p1 = pop()
256
257 if DEBUG_ABS then console.log " abs: " + p1 + " is nothing decomposable"
258 push_symbol(ABS)
259 push(p1)
260 list(2)
261
262 if DEBUG_ABS then console.log " --> ABS of " + input + " : " + stack[tos-1]
263 restore()
264
265# also called the "norm" of a vector
266absval_tensor = ->
267 if (p1.tensor.ndim != 1)
268 stop("abs(tensor) with tensor rank > 1")
269 push(p1)
270 push(p1)
271 conjugate()
272 inner()
273 push_rational(1, 2)
274 power()
275 simplify()
276 Eval()