{dec} ##.cxsh stop ⍝ Complex shell.
Quote-quad input is interpreted as a complex expression; evaluated using operat-
or →cx←; and the result displayed. The input-eval-display loop continues until
terminating string [stop] is input.
We can use simple expressions of complex values, with primitive functions
(+ - × ÷ * ⍟ | ⌊ ⌈ ∨ ^ ○ , ⍴ ⌽ ⍉ ⊖ and ..), together with one-line D-functions,
as long as we bear in mind that all numeric arrays have a hidden first axis,
see →cx←.
Notice that the set of primitive functions is extended with dyadic "..", which
is a complex analogy of the →to← function:
2 4 .. 10 ⍝ sequence (1×4-grid) from 2 4 .. to 10.
2 4 6 8 10
mat ← ¯1j1 .. 2j¯1 ⍝ sequence (3×4-grid) from ¯1j1 to 2j¯1.
mat
¯1j1 0j1 1j1 2j1
¯1 0 1 2
¯1j¯1 0j¯1 1j¯1 2j¯1
mat * ÷ 2 ⍝ square root of mat.
0.4551j1.0987 0.7071j0.7071 1.0987j0.4551 1.4553j0.3436
0j1 0 1 1.4142
0.4551j¯1.0987 0.7071j¯0.7071 1.0987j¯0.4551 1.4553j¯0.3436
Optional left argument [dec] (default 10) is the number of decimal places to
display. Restricting the number of decimals, rather than the number of signific-
ant figures, means that numbers close to zero display as 0.
cxsh''
1○○1 ⍝ sin(pi) - should be 0.
0
Compare this with raw APL:
1○○1 ⍝ sin(pi) - should be 0.
1.224606354E¯16
(muse:
The problem with the above result is not that the sin function (1○) is
inaccurate, but that the value for pi on an IEEE machine is accurate to only
1 in 2*53. Increasing sin's argument by one bit in the least significant
position flips the result from just above zero to slightly further below
zero.
decf '400921FB54442D18' ⍝ approx big-endian hex rep of pi.
3.141592654
1○ decf '400921FB54442D18' ⍝ sin of .. .. ..
1.224606354E¯16
1○ decf '400921FB54442D19' ⍝ sin of _adjacent_ IEEE FP number.
¯3.216285745E¯16
)
See →cx← for more information and details of supported functions.
Technical notes:
It is convenient to separate the code into three subfunctions:
- input-display loop,
- expression translation,
- evaluation of translated expression.
with a calling tree:
loop looping function calls:
\
eval evaluation function calls:
\
cexp complex expression translation.
We could code it like this with three named local functions:
cxsh←{ ⍝ Complex shell.
· cexp←{ ⍝ expression translation.
· · ...
· }
· eval←{ ⍝ expression evaluation.
· · rslt←⍎cexp ⍵ ⍝ execute translated expression.
· · ...
· }
· loop←{ ⍝ evaluation loop:
· · in←⍞ ⍝ input next line,
· · ... ⍝
· · ⎕←eval in ⍝ evaulate line.
· · ∇ ⍵ ⍝ ... and so forth.
· }
· loop ⍵ ⍝ loop until ⍵.
}
However, as we allow the shell to assign global names:
i ← 0j1
there is potential for a name-clash with one of cxsh's locals. For example, with
the above coding, all bets would be off if our user typed:
cxsh'stop' ⍝ start cx session
eval ← + ⍝ clobber cxsh's eval function.
... ⍝ all bets off :-(
It is easy to avoid this situation by passing the subsidiary functions as oper-
ands, rather than naming them: ¯¯¯¯¯¯¯
¯¯¯¯¯¯
cxsh←{ ⍝ Complex shell.
· { ⍝ cexp
· · ... ⍝ is an operand to
· }{ ⍝ eval, which
· · rslt←⍎⍺⍺ ⍵ ⍝ evaluates the expression and
· · ... ⍝ is an operand to
· }{ ⍝ loop, which
· · in←⍞ ⍝ inputs the next line,
· · ⎕←⍺⍺ line ⍝ evaluates it,
· · ... ⍝ checks termination
· · ∇ ⍵ ⍝ continues.
· }⍵
}
Then the ⍎ in the eval function has _no_ local names in scope (rslt is created
dynamically following the execution).
Note that with calling tree:
loop looping function calls:
\
eval evaluation function calls:
\
cexp complex expression translation.
loop and eval are coded as monadic operators. It would be equally easy to have
a tree:
loop
/ \
cexp eval
then we would code loop as a _dyadic_ operator and both cexp and eval as operand
functions. In general, any binary tree function calling scheme may be coded in
this way.
Finally, in the interests of tidiness, we wrap the whole loop-eval-cexp derived
function inside an outer function running in a temporary namespace. This means
that created names are _local_ to the cxsh session and disappear when the (cxsh)
session terminates.
cxsh←{ ⍝ Complex shell.
· (⎕NS'').{ ⍝ operate in temp space.
· · { ⍝ cexp
· · · ... ⍝ is an operand to
· · }{ ⍝ eval, which
· · · ... ⍝ is an operand to
· · }{ ⍝ loop.
· · · ...
· · }⍵
· }⍵
}
However, this obliges us to space-qualify external names: →cx←, →subs←, →lcase←
and →to←. For example:
'..' '─'##.subs ⍵ ⍝ input string with [─/..].
Examples:
4 cxsh')' ⍝ start mini-session (4 dec places) ...
2+3 4 5 ⍝ no surprises with ...
5 6 7
0 1 2 3 4 5|7 ⍝ .. real arithmetic.
7 0 1 1 3 2
¯1*÷2 ⍝ sqrt(¯1) → i.
0j1
1j3 + 8j12 ¯2 0j1 ⍝ complex sum,
9j15 ¯1j3 1j4
1j3 - 8j12 ¯2 0j1 ⍝ difference,
¯7j¯9 3j3 1j2
1j3 × 8j12 ¯2 0j1 ⍝ product,
¯28j36 ¯2j¯6 ¯3j1
1j3 ÷ 8j12 ¯2 0j1 ⍝ quotient,
0.2115j0.0577 ¯0.5j¯1.5 3j¯1
1j3 | 8j12 ¯2 0j1 ⍝ residue,
1j1 ¯2 0j1
¯29j53 ∨ ¯1j107 ⍝ gcd,
7j1
¯29j53 ^ ¯1j107 ⍝ lcm.
¯853j¯329
2 1.5 .. ¯1 ⍝ real range.
2 1.5 1 0.5 0 ¯0.5 ¯1
0j¯1 .. 0j2 ⍝ imaginary range.
0j¯1
0
0j1
0j2
cpts ← ¯1j1..1j¯1 ⍝ matrix of compass points.
12 ○ cpts ⍝ phase angles of compass points.
2.3562 1.5708 0.7854
3.1416 0 0
¯2.3562 ¯1.5708 ¯0.7854
⍝ The following few examples probe values of the complex functions around their
⍝ "branch cuts", see →cx← for details:
sr ← 1e¯20 × ¯1j1..1j¯1 ⍝ small region around origin.
sqrt←*∘(÷2) ⍝ square-root function.
sqrt ¯1+sr ⍝ square-root around ¯1.
0j1 0j1 0j1
0j1 0j1 0j1
0j¯1 0j¯1 0j¯1
12○ ¯1+sr ⍝ phase angle around ¯1.
3.1416 3.1416 3.1416
3.1416 3.1416 3.1416
¯3.1416 ¯3.1416 ¯3.1416
¯3○ 0j2+sr ⍝ arctan around 0j2.
¯1.5708j0.5493 ¯1.5708j0.5493 1.5708j0.5493
¯1.5708j0.5493 ¯1.5708j0.5493 1.5708j0.5493
¯1.5708j0.5493 ¯1.5708j0.5493 1.5708j0.5493
⍝ The function for a polygon in the complex plane is particularly simple:
poly←{0j1*(0..⍵-1)×4÷⍵} ⍝ ⍵-polygon.
poly 4 ⍝ square.
1 0j1 ¯1 0j¯1
poly 5 ⍝ pentagon.
1 0.309j0.9511 ¯0.809j0.5878 ¯0.809j¯0.5878 0.309j¯0.9511
2 × poly 4 ⍝ larger square.
2 0j2 ¯2 0j¯2
1j1 × 2 × poly 4 ⍝ rotated larger square.
2j2 ¯2j2 ¯2j¯2 2j¯2
sqrt←{|+∘|/⍵⍴0j1} ⍝ square-root (Theodorus of Cyrene?)
sqrt 2
1.414213562
sqrt 10
3.16227766
⍝ Comparisons using ≡ are OK:
{⍵≡1:⍵ ⋄ 1≡2|⍵:∇1+3×⍵ ⋄ ∇⍵÷2}27 ⍝ →osc←
1
⍝ Here are some more expressions involving i, the square-root of ¯1:
i ← ¯1*÷2 ⍝ the square-root of ¯1 ...
i ⍝ ... is i.
0j1
1 + * ○ i ⍝ 1-plus-e-to-the-i-pi →Euler←.
0
i * ¯2 .. 2 ⍝ powers of i.
¯1 0j¯1 1 0j1 ¯1
i * i ⍝ i-to-the-i is real (!) and the same as ...
0.2079
*-○÷2 ⍝ ... e-to-the-neg-pi-by-two.
0.2079
i*÷i ⍝ likewise, the i'th root of i is real and
4.8105
*○÷2 ⍝ ... is the same as e-to-the-pi-by-two and
4.8105
(+i)*i ⍝ ... the same as conjugate-i-to-the-i and
4.8105
↑*⍨/i i i i ⍝ ... the same as ((i*i)*i)*i.
4.8105
⍝ ix
{(*⍵×0j1)≡(2○⍵)+0j1×1○⍵} ¯1j1 ¯0.9j0.9 .. 1j¯1 ⍝ e = cos(x)+i sin(x)
1
⍝ and finally ...
¯8*÷3 ⍝ principal cube root of ¯8 (see below).
1j1.7321
) ⍝ termination string.
⍝ Compare the last result above with the result of the same expression
⍝ in non-complex APL:
¯8*÷3 ⍝ real cube root of ¯8 (see above).
¯2
⍝ In general, numbers have 2 square roots, 3 cube roots, ... ⍵ ⍵th roots.
⍝ Traditional (non-complex) APL returns:
⍝ the positive real root, if there is one,
⍝ otherwise, the negative real root, if there is one,
⍝ otherwise, it fails with a domain error.
⍝
⍝ Complex APL can generate all ⍵ roots, so it chooses to return the one with the
⍝ smallest positive phase angle.
See also: cx polar esh decf
Back to: contents
Back to: Dyalog APL
Trouble seeing APL font?