Scientific calculator software to introduces complex number operations on the HP-41. Easy to use. Runs in extended memory. Complex numbers are commonly used to simplify the analysis of linear circuits in electrical and mechanical engineering. This program makes complex arithmetic as easy as working with normal numbers on HP-41CV and HP-41CX calculators.\(\)
Features
- Ease of use
- Displays the whole complex number at once
- 15 mathematical, 12 trigonometric, 12 hyperbolic and 10 stack manipulation functions.
- Supports both rectangular and polar mode
- Stack mechanism identical to the normal stack
- Requires only 5 registers of main memory (assuming extended memory is used).
History
In the early 1980’s, I started a complex arithmetic library in Oxford Pascal for the Commodore-64. After hacking up a RS-232 level adjuster for the Commodore-64, I transferred the library to the Pr1me computer on campus. From there, this program grew with me through college.
This program is a variation on Frans de Vries’ Complex Arithmetic program [1]. I moved the code to extended memory and made it more intuitive. The program now shows the result as a condensed complex number and makes the R/S button behave like a COMPLEX prefix to operations.
Twenty-five years later, I restored my faithful HP-41 and use the same program once more. This version is also verified to run under Windows using Warren Furlow’s V41 simulator when compiled with Leo Duran’s hp41uc.
Entering the program
The program consist of two parts. The first part labeled CA
fits in a mere 5 registers of main memory. It handles the initialization and then jumps to the second part labeled X
. This second part should be placed in extended memory, but can also be used in main memory.
Start by freeing up some program memory (SIZE 014). Enter both parts of the program using a wand, magnetic cards, HP-IL or type it in. Pack it (GTO ..), and test the program with XEQ “CA”. This clears the complex stack, initializes relevant flags and angular mode. It then shows the value at the top of the complex stack and waits for input. Assuming all went well, move part 2 to extended memory (“X” SAVEP) and remove line 019 from part 1.
Start the program using XEQ “CA”. Again, this clears the complex stack and initializes flags and angular mode, but this time it will jump to extended memory. It displays the top of the complex stack (Z1), and wait at line 013
where. At this point, you have the option of entering an operand or calling a operation. At the end of each operation it will return to line 013
.
Note that it is not possible to change the program while in extended memory. Once the program executes in extended memory, the bytes near the GTO and XEQ instructions will be changed to match to the corresponding LBL
address. This would cause the check sum of the fill to mismatch. For more details on running a program in extended memory, refer to the book “Extend your HP-41” [6].
Usage
The program makes complex number arithmetic very similar to working with normal numbers. Numbers are entered and returned through a mechanism very similar to the regular stack. The calculating environment consists of 6 complex stack registers, numbered Z1
thru Z6
, and a complex LASTZ1
register. The large complex stack reduces the need for store and recall functions.
The keyboard overlay shown below, gives an overview of the complex number operations.
Operations
Complex operations are called by pressing COMPLEX (the R/S key on the normal keyboard) followed by the desired operation key. In the overlay, the complex operations can be identified by the blue paint splash. In this article, these complex operations are shown in a blue box.
After each operations, the result of the operation is stored on the complex stack as Z1, and shown on the display in a condensed format. To see the full accuracy, press X<>Y to see the imaginary part (or phase in Polar mode), and X<>Y again to see the real part (or modulus in Polar mode).
Most operation require one or two operands from the stack. Exceptions to this rule are functions that take a real number argument (Zn, Z1/n, nZ, VIEWZn, Z1 Zn), the mode switches (RECT, POL) and prefixes (g, ARC, HYP).
The function Z1/n, is a bit different. It will return multiple answers: the nth roots of the complex number in Z1. The ALPHA annunciator indicates that more roots are available. Press COMPLEX to show the next root. If you leave ALPHA-mode to see the root in X and Y in full accuracy, be sure to restore the order of the stack before pressing the R/S key to see the next root. When all roots are displayed, the first root will be available as Z1 on the complex stack (and X,Y on the regular stack).
The use of the prefixes ARC and HYP is similar to the use of the shift key, with flag 03 and 04 acting as the annunciator for ARC and HYP respectively. They can be used in any combination to denote and execute the desired function. The state of these flags only affects trigonometric operations. To squeeze the program (866 bytes) into the x-memory, the operations ATAN, ATANH, ACOT and ACOTH had to be removed.
Note that operations can anywhere between 1 and take up to 6 seconds to execute. Also, BCUT is only implemented in “Complex Arithmetic with adjustable branch cut for HP-41cv/cx“.
Display
After each operations, the result of the operation is stored on the complex stack as Z1, and shown on the display in a condensed format. To see the full accuracy, press X<>Y to see the imaginary part (or phase in Polar mode), and X<>Y again to see the real part (or modulus in Polar mode).
Both rectangular coordinates and polar form are supported for data entry and viewing. To switch between modes, use the RECT and POL operations. These operations also recall Z1 into the normal stack. Flag 0 shown on the LCD display serves as an annunciator for polar mode.
Operands
A few operations, such as Zn, Z1/n, nZ, VIEWZn and Z1 Zn require a real number operand in the X register. Most other operations use a complex number operand.
Complex numbers can either be entered on the regular stack as an X,Y pair on the normal stack. In rectangular mode, the real part of the complex number in should be placed in X register and the imaginary part in Y. In polar mode, the magnitude should be in X and the phase in Y.
If no complex number is entered on the normal stack, the operation will take the value from the complex stack.
Error handling
The program has no accommodation (apart from the SF 25 at line 040 in “X”) to avoid error halts. This implies that attempts to divide by zero, take the log of zero, etc. will usually cause a DATA ERROR halt. Pressing INIT lets the program return to its normal halting point at line 013 in “X”.
Examples
The following examples assume a ENG 3, SF 28 and CF 29 display mode.
Calculate \((2 + 3j)(7 – 6j) + (4 + 5j)\)
Key strokes | Display |
---|---|
input | display |
XEQ “CA” | 0.00E0+0.00E0J |
3 ENTER | 3.000 |
2 COMPLEX ENTER | 2.00E0+3.00E0J |
6 CHS | |
ENTER | -6.000 |
7COMPLEX * | 32.0E0+9.00E0J |
5 ENTER | 5.000 |
4 COMPLEX + | 36.0E0+14.0E0J |
X Y | 36.000 |
X Y | 14.000 |
The answer is \(36 + 14j\)
Calculate \((3 + 4.5j)^5\)
Key strokes | Display |
---|---|
input | display |
4.5 ENTER | 4.500 |
3 COMPLEX ENTER | 3.00E0+4.50E0J |
5 COMPLEX ZN | 926.E0-4.53E3J |
X Y | -4.533 03 |
X Y | 926.4 00 |
The answer is \(926.4 – 4.533j\)
Show what is in the LASTZ1 complex register
Key strokes | Display |
---|---|
COMPLEX LASTZ1 | 3.00E0+4.50E0J |
Note that the complex number is saved, not the power 5
Calculate \(\frac{1}{3\ \angle 30^o}\)
Key strokes | Display |
---|---|
COMPLEX POL | 5.41E0<56.3E0 |
40 ENTER | 40.00 00 |
3 COMPLEX 1/Z | 333.E-3<-40.0E0 |
The answer is \(0.333\ \angle{-40}^o\)
Calculate \(asinh(8 – 5j)\)
Key strokes | Display |
---|---|
COMPLEX RECT | 255.E-3-214.E-3J |
5 CHS | |
ENTER | -5.000 00 |
8 COMPLEX ARC | |
HYP SIN | 2.94E0-556.E-3J |
The first answer is still there
input | display |
5 COMPLEX Z1 Zn | 94E0-556.E-3J |
Calculate \(\sqrt[3]{5 + 3j}\)
Key strokes | Display |
---|---|
3 ENTER | 3.000 00 |
5 COMPLEX VIEW | 5.00E0+3.00E0J |
3 COMPLEX Z1/n | 1.77E0+322.E-3J (alpha) |
COMPLEX | -1.16E0+1.37E0J (alpha) |
COMPLEX | -606.E-3-1.69E0J (alpha) |
COMPLEX | 1.77E0+322.E-3J |
Calculate \(csch(1 + 2j)\)
Key strokes | Display |
---|---|
2 ENTER | 2.000 00 |
1 COMPLEX HYP CSC | -489.E-3+1.40E0J |
Calculate \(\ln(4 + 5j) + (3 – 2j)^{(2 – 3j)}\)
Key strokes | Display |
---|---|
5 ENTER | 5.000 00 |
4 COMPLEX LN | 1.86E0+896.E-3J |
2 CHS | |
ENTER | -2.000 00 |
3 COMPLEX ENTER | 3.00E0-2.00E0J |
3 CHS | |
ENTER | -3.000 00 |
2 COMPLEX Z2Z1 | -1.79E-3-3.19E-3J |
COMPLEX + | 1.85E0+893.E-3J |
Calculate \(2^{3+4j}\)
Key strokes | Display |
---|---|
4 ENTER | 4.000 00 |
3 COMPLEX ENTER | 3.00E0+4.00E0J |
2 COMPLEX NZ | -7.46E0+2.89E0J |
The number \(N\) must always be the last one that is entered.
Tweaks
- The input/output angular mode for polar coordinates is set in line 004 of program “CA”, Default is DEG, change to RAD for radians.
- The size of the complex stack can be adjusted in line 008 of program “CA”.
- If flag 14 is set when calling “CA”, the stack will not be cleared, which may be useful if you left “CA” temporarily and want to continue. This however assumes that the data registers used for the complex stack are left undisturbed.
- The program uses flag 22 “numeric entry” to determine if there is a new entry in X,Y. If there is a numeric entry, the number is first pushed onto the complex stack, respecting stack lift status. This implies that you can clear flag 22 manually if you have made an accidental digit entry and still want the next operation to be performed on the current Z1.
- Operands that require a real number input, will always take that number from the X register, new entry or not. If stack lift is disabled, the stack will first be shifted down, so the function will be performed on Z2. This is done, so that you may have ENTER ‘ed the complex number on which you want the function to be executed, and without the shift down there would be left a superfluous copy of that number on the stack.
Source code
Ángel Martin combined several of my focal programs from this site and compiled ROM and MOD images. They are available through GitHub. Note that this program consists of two parts.
- Part 1 should be placed in main memory and is available as source code, raw for the V41 emulator and barcode for the HP Wand (HP82153A)
- Part 2, can be placed in either main or extended memory. When placed in extended memory, the instruction GTO “X” should be removed. This part is available as source code, raw for the V41 emulator and barcode for the HP Wand.
- Requires X-Functions module on the HP-41cv
- The keyboard overlay is available as image and inverted. These are scaled down by 98% so when printed on 4×6″, it typically comes out as true-size.
Available through the repository
part 1
; The program consists of two parts. The part listed below should be in main ; memory. The other part (listed in CA300xm.txt) can be placed in either main ; or extended memory. When placed in extended memory, THE INSTRUCTION GTO "X" ; SHOULD BE REMOVED. ; ; Before placing the second part in XM, the program should be PACKed ; and run in RAM. This should be done to compile all the GTO's and ; XEQ's. If this is not done one will see CHKSUM ERR when trying to ; download this program into RAM. [9] 1 LBL "CA" 2 CF 03 ; clear prefix flags (ARC, HYP) 3 CF 04 4 DEG 5 FS? 14 ; if the "do not clear stack" flag is set 6 GTO 00 ; then jump to LBL 00, 7 SIZE? ; else if needed extended the # of data registers (NEW: LINE REMOVED) 8 6 9 STO 00 10 ST+ X 11 3 12 + 13 X>Y? 14 PSIZE 15 CLX 16 STO 01 ; clear LASTZ 17 STO 02 18 LBL 00 19 GTO "X" ; REMOVE THIS LINE when LBL "X" in X-memory !! 20 "\8D\BE" 21 RCL M 22 STO b ; jump to "X" in extended memory at address 0x8DBE 22 END
part 2
-
Stack and alpha registers:
- The program uses all registers
-
Data registers:
- R00, depth of complex stack (default value is 6)
- R01, real part of LASTZ1
- R02, imaginary part of LASTZ1
- R03, real part of complex number Z1
- R04, imaginary part of complex number Z1
- :
- R13, real part of complex number Z6
- R14, imaginary part of complex number Z6
- Note that the internal format of the complex stack is always rectangular.
-
Flags:
- flag 00, “POL”, when set indicates Polar notation (POL), otherwise rectangular notation (RECT)
- flag 02, “no stack lift”, when set disables the stack lift
- flag 03, “ARC”, when set indicates inverse trigonometric operation (ARC)
- flag 04, “HYP”, when set indicates hyperbolic operation (HYP)
- flag 10, “alt operation”, allows similar operations to reuse code
- flag 14, “clipped corner”, is used for all but magnetic cards. During initialization it indicates “do not clear stack”; during keyboard fetching it indicates more key strokes need to follow; and during trigonometry operations, indicates inverse operation.
- flag 22, “keyboard input”, set when numeric input is entered from the keyboard, cleared on power cycle. [7]
- flag 25, “ignore error”, when set, ignores improper operations (like div by zero) or range errors.
- flag 30, used for “always false” test. Used to negate prior test. [7]
- flag 47, “shift set”, used internally in shifted operations.
- flag 44-46, cleared as a side effect of showing the “shift” annunciator
- flag 48-55, cleared as a side effect of showing the “shift” annunciator
-
Legend:
- (x + y.j), complex number held on the regular stack
- X register holds the real part (x)
- Y register holds the imaginary part (y)
- (M . e^j.phi), complex number in polar notation
; INITIALIZE AND MAIN LOOP ; ; An infinite loop to fetch a keystroke identifying the operation to be ; executed. The "shift" key causes the "shift" status to be toggled, for all ; other keys the LBL that matches the key code will be called (or keycode+5 if ; "shift" was active). ; ; called : from "CA" in main memory, or ; in response to [CINIT] keycode (labeled [ON] on keyboard) ; on entry : when flag 14 is set, the complex stack will not be cleared ; on exit : value of Z1 shown. Also available as X,Y. 1 LBL "X" 2 RDN 3 FC?C 14 ; if the "do not clear stack" flag is not set 4 XEQ 48 ; then clear the complex stack 5 LBL 01 ; [CINIT] operation 6 CF 10 7 CF 22 8 CF 25 9 FS? 00 10 R-P 11 XEQ 10 ; display complex number (x + y.j) 12 STOP 13 ENTER^ 14 LBL 02 15 CLX 16 GETKEY ; wait for an operation keycode 17 X=0? 18 GTO 02 19 31 20 X#Y? ; if not the "shift" key 21 GTO 00 ; then handle that operation 22 R^ ; else update the shift annunciator 23 R^ 24 "\01\00" 25 FS? 47 26 CLA 27 RCLFLAG 28 ASTO d 29 STOFLAG 30 AOFF 31 GTO 02 32 LBL 00 ; handle operation associated with a keycode 31 CLX 34 5 35 FC? 47 ; if "shift was active" 36 CLX ; then increment key code by 5 37 + 38 RDN 39 CLD 40 SF 25 41 XEQ IND T ; call the corresponding operation 42 FC?C 14 43 GTO 01 44 ENTER^ 45 GTO 02 ; TOGGLE [ARC] MODIFIER, for ASIN, ACOS, ATAN 46 LBL 11 ; [ARC], key label [sigma+] 47 FC?C 03 48 SF 03 49 SF 14 ; indicate "more key strokes to follow" 50 RTN ; TOGGLE [HYP] MODIFIER, for SINH, COSH and TANH 51 LBL 16 ; [HYP], key label [sigma-] 52 FC?C 04 53 SF 04 54 SF 14 ; indicate "more key strokes to follow" 55 RTN ; SWITCH BETWEEN POLAR AND RECTANGULAR NOTATION 56 LBL 68 ; [RECT], key label [P>R] 57 CF 00 58 GTO 00 59 LBL 69 ; [POL], key label [R>P] 60 SF 00 61 LBL 00 62 RCL 04 ; get Z1 from the complex stack as (x + y.j) 63 RCL 03 64 RTN ; COMPLEX RECIPROCAL (1/Z) ; ; on entry : Z in X,Y registers in the form (x + y.j) ; on exit : the result is stored as Z1 on the complex stack ; the result is stored in X,Y in the form (x + y.j) ; LASTZ1 holds a copy of the operation operand Z 65 LBL 12 ; [1/Z] operation 66 XEQ 09 ; push (x + y.j) onto complex stack and update LASTZ1 67 XEQ 31 ; compute (x + j.y) = 1 / (x + j.y) 68 GTO 03 ; copy (x + y.j) to complex stack, and return ; COMPLEX ENTER^ ; ; on entry : Z in X,Y registers in the form (x + y.j) ; on exit : Z is pushed up the complex stack as Z1 and Z2 ; Z is X,Y in the form (x + y.j) ; LASTZ1 is unchanged 69 LBL 41 ; [CENTER^] operation 70 XEQ 04 ; push (x + y.j) onto complex stack 71 XEQ 11 ; move complex stack up, Z1 > Z2 > Z3 > Z4 > Z5 > Z6 72 SF 02 ; "no stack lift" 73 RTN ; COMPLEX CLEAR STACK ; ; on entry : n/a ; on exit : Z1..Z6 on the complex stack are set to (0 + 0j) ; LASTZ1 is unchanged 74 LBL 48 ; [CCLST] operation 75 RCL 00 76 ISG X 77 "" 78 ST+ X 79 E3 80 / 81 3 82 + 83 . 84 LBL 36 85 STO IND Y 86 ISG Y 87 GTO 36 88 CF 02 ; no "no stack lift" 89 CLST 90 RTN ; COMPLEX CHANGE SIGN AND COMPLEX CONJUGATE (Complement) ; ; -(x + y.j) = -x - y.j (change sign) ; (x + y.j)* = x - y.j (conjugate) ; ; on entry : Z in X,Y registers in the form (x + y.j) ; on exit : the result is stored as Z1 on the complex stack ; the result is stored in X,Y in the form (x + y.j) ; LASTZ1 holds a copy of the operation operand Z 91 LBL 42 ; [CHSZ] operation 92 SF 10 93 LBL 47 ; [COMPLZ] operation 94 XEQ 04 ; push (x + y.j) onto complex stack 95 FS? 10 96 CHS 97 X<>Y 98 CHS 99 X<>Y 100 GTO 03 ; copy (x + y.j) to complex stack, and return ; CLEAR Z1 ; ; on entry : Z in X,Y registers in the form (x + y.j) ; on exit : Z is pushed up the complex stack as Z1 and Z2 ; Z is X,Y in the form (x + y.j) ; LASTZ1 is unchanged 101 LBL 49 ; [CLZ1] operation 102 XEQ 04 ; push (x + y.j) onto complex stack 103 CLST 104 SF 02 ; "no stack lift" 105 GTO 03 ; copy (x + y.j) to complex stack, and return ; LAST Z1 ; ; on entry : n/a ; on exit : the operand from the last numeric operation (except CHSZ) ; is pushed onto the complex stack ; the operand from the last numeric operation (except CHSZ) ; is stored in X,Y in the form (x + y.j) 106 LBL 88 ; [LASTZ1] operation 107 FS? 02 108 FS? 22 ; if "no stack lift" or "input from keyboard" 109 XEQ 41 ; then perform ENTER^ 110 CF 02 111 RCL 02 ; LASTZ1 112 RCL 01 113 GTO 03 ; copy (x + y.j) to complex stack, and return ; COMPLEX ADDITION AND SUBTRACTION ; ; (z + t.j) + (x + y.j) = (x + z) + j.(y + t) ; (z + t.j) - (x + y.j) = (x - z) + j.(y - t) ; ; on entry : if number was entered on the keyboard, ; then (x + y.j) as entered in X,Y registers, and ; (z + t.j) from Z1 on the complex stack ; else (x + y.j) from Z1 on the complex stack, and ; (z + t.j) from Z2 on the complex stack ; on exit : the result is stored as Z1 on the complex stack ; the result is stored in X,Y in the form (x + y.j) ; LASTZ1 holds a copy of (x + y.j) 114 LBL 51 ; [C-] operation 115 SF 10 116 LBL 61 ; [C+] operation 117 XEQ 07 ; get two operands, as (x + j.y) and (z + j.t) 118 FS? 10 119 CHS 120 X<>Y 121 FS? 10 122 CHS 123 ST+ T 124 RDN 125 + 126 GTO 03 ; copy (x + y.j) to complex stack, and return ; COMPLEX MULTIPLICATION AND DIVISION ; ; Z2 * Z1 = (re1 + j.im1) * (re2 + j.im2) = ; = (re1.re2 - im1.im2 ) + j.(im1.re1 + re1.im2) ; ; Z2 / Z1 = Z2 * 1/Z1 127 LBL 81 ; [C/] operation 128 SF 10 129 LBL 71 ; [C*] operation 130 XEQ 07 ; get two operands, as (x + j.y) and (z + j.t) 131 FS? 10 ; if division 132 XEQ 31 ; then compute (x + j.y) = 1 / (x + j.y) 133 XEQ 00 ; compute (x + j.y) * ( z + j.t) 134 GTO 03 ; copy (x + y.j) to complex stack, and return ; COMPLEX POWER OF A COMPLEX NUMBER ; ; (x+y.j) z -t.phi1 j.(z.phi1 + t.ln(r1)) ; (z+t.j) = r1 . e . e ; ; where: ; r1 = sqrt(x^2+y^2) ; phi1 = .... x + y.j ....???? 135 LBL 17 ; [Z2^Z1] operation 136 XEQ 07 ; get two operands, as (x + j.y) and (z + j.t) 137 R^ 138 R^ 139 RAD 140 R-P 141 LN 142 XEQ 00 ; compute (x + j.y) * ( z + j.t) 143 E^X 144 P-R 145 GTO 03 ; copy (x + y.j) to complex stack, and return ; COMPLEX PARALLEL CIRCUIT, useful in network theory ; ; Z1 . Z2 ; Z1 // Z2 = ------- {for |Z1+Z2| <> 0} ; Z1 + Z2 146 LBL 32 ; [CPAR] operation 147 XEQ 07 ; get two operands, as (x + j.y) and (z + j.t) 148 XEQ 31 ; compute 1 / ( x + j.y) 149 R^ 150 R^ 151 XEQ 31 ; compute 1 / ( x + j.y) 152 X<>Y 153 ST+ T 154 RDN 155 + 156 XEQ 31 ; compute 1 / ( x + j.y) ; REPLACE Z1 with (x + y.j) ON COMPLEX STACK 157 LBL 03 ; [PRGM] keycode 158 DEG ; switch to DEG mode 159 STO 03 160 X<>Y 161 STO 04 162 X<>Y 163 RTN ; MULTIPLY TWO COMPLEX NUMBERS subroutine ; ; (x + y.j) * (z + t.j) = (x + j.y) * (z + j.im2) = ; = (x.z - y.t ) + j.(y.x + x.t) 164 LBL 00 165 STO L 166 R^ 167 ST* L 168 X<> Z 169 ST* Z 170 R^ 171 ST* Y 172 ST* Z 173 X<> L 174 + 175 X<> Z 176 - 177 RTN ; COMPLEX COMMON (base 10) and NATURAL (base e) LOGARITHM ; ; ln(x + y.j) = ln(r) + j.phi ; ; Z1 ; log(Z2) = ln(Z2) / ln(Z1) 178 LBL 14 ; [LOG(Z)] operation 179 XEQ 08 ; get operand, as (x + j.y) and update LASTZ 180 LN ; x=ln(M1), y=phi1 181 GTO 00 182 LBL 15 ; [LN(Z)] operation 183 XEQ 09 ; push (x + y.j) onto complex stack and update LASTZ 184 E ; x=1 185 LBL 00 186 RDN 187 RAD 188 R-P 189 LN 190 R^ 191 ST/ Z 192 / 193 GTO 03 ; copy (x + y.j) to complex stack, and return ; COMPLEX COMMON (base 10) and NATURAL (base e) EXPONENTIAL ; ; (x + j.y) x x ; e = e .sin(y) + j.e .cos(y) 194 LBL 19 ; [n^Z] operation 195 XEQ 08 ; get operand, as (x + j.y) and update LASTZ 196 LN 197 GTO 00 ; reuse part of [E^Z] operation 198 LBL 20 ; [E^Z] operation 199 XEQ 09 ; push (x + y.j) onto complex stack and update LASTZ 200 E 201 LBL 00 202 ST* Z 203 * 204 E^X 205 RAD 206 P-R 207 GTO 03 ; copy (x + y.j) to complex stack, and return ; COMPLEX EXPONENTIATION WITH REAL EXPONENT n 208 LBL 18 ; [Z^n] operation 209 XEQ 08 ; get operand, as (x + j.y) and update LASTZ 210 RDN 211 R-P 212 R^ 213 ST* Z 214 Y^X 215 P-R 216 GTO 03 ; copy (x + y.j) to complex stack, and return ; COMPLEX ROOT OF REAL NUMBER n ; __ ; Z1/ 1/Z1 ; \/ Z2 = Z2 ; __ ; n / 1/n j.(phi/n) ; \/ Z = M . e 217 LBL 13 ; [Z^1/n] operation 218 XEQ 08 ; get operand, as (x + j.y) and update LASTZ 219 RDN 220 R-P 221 R^ 222 1/X 223 Y^X 224 360 225 R^ 226 ST/ T 227 ST/ Y 228 R^ 229 R^ 230 LBL 05 231 FC? 00 232 P-R 233 XEQ 10 ; display complex number (x + y.j) 234 AON 235 STOP 236 FC? 00 237 R-P 238 R^ 239 ST+ Z 240 RDN 241 DSE Z 242 GTO 05 ; loop back to LBL 05 243 P-R 244 AOFF 245 GTO 03 ; copy (x + y.j) to complex stack, and return ; COMPLEX SINE, COSECANT, COSINE AND SECANT ; ; sin( x + j.y) = sin(x).cosh(y) + j.cos(x).sinh(y) ; cos( x + j.y) = cos(x).cosh(y) - j.sin(x).sinh(y) ; sinh(x + j.y) = cos(y).sinh(x) + j.sin(y).cosh(x) ; cosh(x + j.y) = cos(y).cosh(x) + j.sin(y).sinh(x) ; csc(x + j.y) = 1 / sin( x + j.y) ; sec(x + j.y) = 1 / cos( x + j.y) ; csch(x + j.y) = 1 / sinh(x + j.y) ; sech(x + j.y) = 1 / cosh(x + j.y) ; ; Flags used: ; flag 04, indicates [HYP] ; flag 10, indicates [SIN], otherwise [COS] ; flag 14, indicates inverse operation (CSC and COS, aka SIN^-1 and COS^-1) ; ; Reference: ; https://en.wikipedia.org/wiki/Complex_number#Complex_analysis 246 LBL 28 ; [CSC(Z)] operation 247 SF 14 248 LBL 23 ; [SIN(Z)] operation 249 SF 10 250 LBL 29 ; [SEC(Z)] operation 251 FC? 10 252 SF 14 253 LBL 24 ; [COS(Z)] operation 254 XEQ 09 ; push (x + y.j) onto complex stack and update LASTZ 255 FS?C 03 ; ARC? 256 GTO 13 257 XEQ 00 ; calculate cos/sin/cosh/sinh 258 ST* T 259 RDN 260 * 261 CHS 262 FC? 04 ; HYP? 263 FS? 10 ; SIN? 264 CHS 265 FC?C 04 ; HYP? 266 FC? 10 ; COS? 267 X<>Y 268 FS?C 14 ; inverse operation? 269 XEQ 31 ; then compute Z1 = 1 / Z1 270 GTO 03 ; copy (x + y.j) to complex stack, and return ; COMPLEX TANGENT AND COTANGENT, doesn't support ARC or HYP variations ; ; tan(x + j.y) = sin(2.x) / ( cosh(2.y) + cos(2.x) ) + ; sinh(2.y) / ( cosh(2.y) + cos(2.x) ) . j ; cot(Z) = 1 / tan(Z) ; ; Flags used: ; F03 indicates [ARC] ; F04 indicates [HYP] ; F14 indicates inverse operation (COT aka TAN^-1] 271 LBL 30 ; [COT(Z)] operation 272 SF 14 273 LBL 25 ; [TAN(Z)] operation 274 FS?C 03 ; ARC? 275 GTO 02 ; UNSUPPORTED, jump back to main routine 276 FS?C 04 ; HYP? 277 GTO 02 ; UNSUPPORTED, jump back to main routine 278 XEQ 09 ; push (x + y.j) onto complex stack and update LASTZ 279 2 ; multiply x and y by 2 280 ST* Z 281 * 282 XEQ 00 ; calculate cos/sin/cosh/sinh (F04=0, F10=0) 283 R^ 284 + 285 ST/ Z 286 / ; answers is now as (x + y.j) 287 FS?C 14 ; inverse operation? 288 XEQ 31 ; then compute Z1 = 1 / Z1 289 GTO 03 ; copy (x + y.j) to complex stack, and return ; TRIGONOMIC OPERATIONS HELPER subroutine ; ; Call with: ; complex number on the stack as (x + y.j). ; F04 indicates [HYP] ; F10 indicates [SIN], otherwise [COS] ; ; This operation returns: ; ; | [HYP] [HYP] ; | [SIN] [COS] [SIN] [COS] ; ------+---------------------------------- ; re y-reg | sin(y) sin(y) sin(x) sin(x) ; re z-reg | cosh(x) sinh(x) cosh(y) sinh(y) ; ------+---------------------------------- ; im x-reg | cos(y) cos(y) cos(x) cos(x) ; im t-reg | sinh(x) cosh(x) sinh(y) cosh(y) ; ; x -x 2.x ; e - e e - 1 1 ; sinh(x) = --------- = --------- , csch(x) = ------- ; x sinh(x) ; 2 2.e ; ; x -x 2.x ; e + e e + 1 1 ; cosh(x) = --------- = --------- , sech(x) = ------- ; x cosh(x) ; 2 2.e ; Reference: ; https://en.wikipedia.org/wiki/Hyperbolic_trig_operations 290 LBL 00 291 FS? 04 ; HYP? 292 X<>Y ; 293 2 294 RCL Z 295 ST+ X 296 E^X-1 297 ST+ Y 298 R^ 299 E^X 300 ST+ X 301 ST/ Z 302 / 303 FS? 10 ; SIN? (not COS) 304 X<>Y ; 305 R^ 306 RAD 307 SIN 308 R^ 309 COS 310 RTN ; INVERSE TRIGONOMIC OPERATIONS, ARC and HYP-ARC ; ; arcsin(x + y.j) = arcsin(b) + j.sign(y).ln(a + sqrt(a^2-1) ; arccos(x + y.j) = arccos(b) - j.sign(y).ln(a + sqrt(a^2-1)) ; arccsc(Z) = arcsin(1/Z) ; arcsec(Z) = arccos(1/Z) ; arcsinh(Z) = -j.arcsin(j.Z) ; arccosh(Z) = j.arccos(Z) ; arccsch(Z) = j.arccsc(j.Z) ; arcsech(Z) = j.arcsec(Z) ; where ; a = ( sqrt( (x+1)^2 + y^2 ) + sqrt( (x-1)^2 + y^2) ) / 2 ; b = ( sqrt( (x+1)^2 + y^2 ) - sqrt( (x-1)^2 + y^2) ) / 2 ; sign(y) returns 1 when y>=0, otherwise returns -1 ; ; Flags used: ; F04 indicates [HYP] ; F10 indicates [SIN], otherwise [COS] ; F14 indicates inverse operation (CSC and COS, aka SIN^-1 and COS^-1] ; ; Reference: ; https://en.wikipedia.org/wiki/Inverse_trigonometric_operation 311 LBL 13 312 FS?C 14 ; inverse operation? 313 XEQ 31 ; compute Z1 = 1 / Z1 314 FS? 04 ; HYP flag 315 FC? 10 316 GTO 00 317 X<>Y 318 CHS 319 LBL 00 ; entered with Z1 as (x + y.j) 320 RCL X 321 E 322 ST- Z 323 + 324 X^2 325 X<>Y 326 X^2 327 X<> Z 328 X^2 329 ST+ Z 330 + 331 SQRT 332 STO Z 333 X<>Y 334 SQRT 335 ST- Z 336 + 337 2 338 ST/ Z 339 / ; X holds a; Y holds b; Z holds y 340 ENTER^ 341 X^2 342 SIGN 343 ST- L 344 X<> L 345 SQRT 346 + 347 LN 348 R^ 349 SIGN 350 * 351 FC? 10 352 CHS 353 X<>Y 354 RAD 355 FS? 10 356 ASIN 357 FC? 10 358 ACOS ; Z1 (x + y.j) now holds the answer to simple ARCSIN or ARCCOS 359 FC?C 04 360 GTO 03 ; we're done for non-HYP operations; 361 FS? 10 ; proceed for for HYP or inverse-HYP 362 CHS 363 X<>Y 364 FC? 10 365 CHS 366 GTO 03 ; copy (x + y.j) to complex stack, and return ; VIEW COMPLEX NUMBER Zn 367 LBL 89 ; [VIEWZn] operation 368 RCL 00 369 X<Y? ; if n > complex stack depth, recall Z1 and return 370 GTO 14 ; get (x + y.j) from complex stack, and return 371 SIGN 372 + 373 ST+ X 374 SIGN 375 CLX 376 RCL IND L ; recall imaginary part of Zn 377 DSE L 378 RCL IND L ; recall real part of Zn 379 FS? 00 ; if notation selected 380 R-P ; then convert to polar notation 381 XEQ 10 ; display complex number (x + y.j) 382 PSE ; pause, but allow number input 383 GTO 14 ; get (x + y.j) from complex stack, and return ; EXCHANGE COMPLEX STACK REGISTERS 384 LBL 21 ; [Z1<>Z2] operation 385 XEQ 04 ; push (x + y.j) onto complex stack 386 2 387 LBL 26 ; [Z1<>Zn] operation 388 RCL 00 389 X<Y? 390 GTO 14 ; get (x + y.j) from complex stack, and return 391 X<>Y 392 ST+ X 393 1.003002 ; X register holds 1.003002; Y register holds 2.n, 394 CF 02 ; no "no stack lift" 395 GTO 00 ; perform register swap and return ; COMPLEX STACK ROLL, up or down ; ; Does not roll around ; Uses block rotate trick form PPC Journal V10N3p15a 396 LBL 22 ; [CR^] operation 397 SF 10 398 LBL 27 ; [CRDN] operation 399 XEQ 04 ; push (x + y.j) onto complex stack 400 3 401 ENTER^ 402 5 403 FS? 10 ; CR^? 404 X<>Y 405 RCL 00 ; complex stack depth (csdepth) 406 DSE X 407 ST+ X 408 E3 409 ST/ Z 410 X^2 411 / 412 + ; for CRDN 413 LBL 00 414 + 415 REGSWAP ; register swap for sss.dddnnn ; GET (x + y.j) FROM COMPLEX STACK 416 LBL 14 417 RCL 04 ; imaginary part of Z1 418 RCL 03 ; real part of Z1 419 RTN ; COMPLEX 1/Z1 ; ; Formula: ; 1 x y ; ------- = --------- - j . --------- ; x + y.j x^2 + y^2 x^2 + y^2 ; ; doesn't disturb Z and T 420 LBL 31 421 X^2 422 X<>Y 423 STO M 424 ST* X 425 ST+ Y 426 X<> M 427 CHS 428 X<>Y 429 ST/ Y 430 ST/ L 431 X<> L 432 RTN ; GET TWO OPERANDS as (x + j.y) and (z + j.t) ; 1st operand is from keyboard, otherwise from Z1 ; stack management subroutine for operations with two complex number operands 433 LBL 07 434 XEQ 06 ; get one operand (x + y.j) from keyboard input ; otherwise from Z1 on the complex stack 435 FC?C 02 436 FC? 22 ; if "no stack lift" or no "input from keyboard" 437 XEQ 12 ; then move complex stack down 438 RCL 04 ; get operand (z + t.j) from Z1 on the complex stack 439 RCL 03 440 R^ 441 R^ 442 GTO 00 ; GET OPERAND, as (x + j.y) and UPDATE LASTZ ; stack management subroutine for operations with one complex and one real number operand 443 LBL 08 ; called with n in register X 444 FS?C 02 ; if "no stack lift" 445 XEQ 12 ; then move complex stack down, Z1 < Z2 < Z3 < Z4 < Z5 < Z6 446 RCL 04 ; copy Z1 to LASTZ 447 STO 02 448 RCL 03 449 STO 01 450 RCL Z ; n in register X, complex operand as (y + z.j) 451 RTN ; PUSH (x + y.j) ONTO COMPLEX STACK and UPDATE LASTZ ; stack management subroutine for operations with one complex number operand 452 LBL 09 453 XEQ 04 ; push (x + y.j) onto complex stack 454 LBL 00 455 STO 01 ; copy to LASTZ1 456 X<>Y 457 STO 02 458 X<>Y 459 RTN ; COMPLEX ALPHA/ALPHA ROUTINE 460 LBL 04 ; [CVIEW] key code [ALPHA] 461 FC?C 02 462 FC? 22 463 FS? 30 ; if both "no stack lift" and "keyboard input" 464 XEQ 11 ; then move complex stack up, Z1 > Z2 > Z3 > Z4 > Z5 > Z6 465 XEQ 06 ; get one operand 466 STO 03 467 X<>Y 468 STO 04 469 X<>Y 470 RTN ; GET ONE OPERAND (x + y.j) ; from keyboard input, otherwise from Z1 on the complex stack 471 LBL 06 472 FS? 00 ; if in polar mode, then convert it to Rect 473 FC? 22 474 FS? 30 475 P-R 476 FS? 22 ; keyboard input? 477 RTN 478 RCL 04 479 RCL 03 480 RTN ; DISPLAY ; in rectangular mode "x + y.j", or in polar mode "x <y" with the ; angle in degrees ; subroutine that views both parts of the complex number in X and Y in ; condensed format in the display, without disturbing Z, T or the display ; mode. ENG 2 was chosen because, to display complex numbers in analog ; electronics. 481 LBL 10 ; Z1 = x + j.y 482 SIGN ; save X in LASTX 483 RDN 484 CLA 485 RCLFLAG ; save flags 486 ENG 2 487 ARCL L 488 RDN 489 FS? 00 ; in Rectangular notation append real part, 490 GTO 00 ; and '+' sign if imaginary part is positive 491 X<0? 492 GTO 00 493 >"+" 494 LBL 00 495 R^ 496 FS? 00 ; for Polar notation, append angle ('<') sign 497 >" <" 498 ARCL Y 499 FC? 00 500 >"J" ; in Rectangular notation append 'J' char 501 AVIEW 502 STOFLAG ; restore flags 503 X<> L ; restore X from LASTX 504 RTN ; ROLL THE COMPLEX STACK, by one position up or down ; subroutine to shift the stack up or down by one complex register ; ; Does not roll around like RDN or R^ ; Does not enter or retrieve data. ; ; Example: ; | stack lift | stack drop ; --------------+------------+------------ ; Z6 6 + 6j | 5 + 5j | 6 + 6j ; Z5 5 + 5j | 4 + 4j | 6 + 6j ; Z4 4 + 4j | 3 + 3j | 5 + 5j ; Z3 3 + 3j | 2 + 2j | 4 + 4j ; Z2 2 + 2j | 1 + 1j | 3 + 3j ; Z1 1 + 1j | 1 + 1j | 2 + 2j 505 LBL 11 ; stack lift, Z1 > Z2 > Z3 > Z4 > Z5 > Z6 506 3.005 ; typically when a new number is moved into Z1 507 GTO 00 508 LBL 12 ; stack drop, Z1 < Z2 < Z3 < Z4 < Z5 < Z6 509 5.003 ; typically when a operation combines Z1 and Z2 510 LBL 00 511 SIGN 512 RCL 00 ; complex stack depth (csdepth) 513 X<>Y 514 ST- Y 515 RDN 516 ST+ X 517 E6 518 ST/ Y 519 X<> L 520 + ; register X is in sss.dddnnn format 521 REGMOVE ; copies 2*(csdepth-1) registers from sss to ddd 522 RDN 523 END
Operations and stack
The table shows the key assignments with their effect on the complex stack.
operation | normal key | description | stack |
COMPLEX | R/S | Prefix for Complex operations. | N |
INIT | ON | Reinitialize, but do not clear stack. | |
+ | + | Adds Z1 to Z2. | E,L,↓ |
/ | * | Multiplies Z2 by Z1. | E,L,↓ |
/ | / | Divides Z2 by Z1. | E,L,↓ |
// | XEQ | Take Z1 and Z2 parallel (network theory). | E,L,↓ |
CHS | CHS | Negate Z1. | E |
CON | ISG | Complement/conjugate of Z1. | E |
1/Z | 1/X | Reciprocal of Z1. | E |
Z2Z1 | yx | Z2 to the power Z1. | E,L,↓ |
LOG | LOG | Base 10 logarithm of Z1. | E,L |
LN | LN | Natural logarithm of Z1. | E,L |
eZ | ex | e to the power Z1. | E,L |
Zn | x2 | Z1 to the real number power n. | E,L |
Z1/n | √x | All nth roots of Z1. | E,L |
nZ | 10x | Real number N to the power Z1. | E,L |
RECT | P→R | Sets the input/output mode to rectangular. | N |
POL | R→P | Sets the input/output mode to polar. | N |
ENTER | ENTER | Lifts the stack and disables stack left. | D,↑,(↑) |
VIEW | ALPHA | Enters a new complex number on the stack without lifting the complex stack (compare to the use of ALPHA/ALPHA to terminate digit entry without using ENTER . Recalls Z1 if flag 22 is clear. | E,(↑) |
CLZ1 | CLX | Clears Z1 and disables stack lift. | D |
CLST | RTN | Clears the complex stack and the normal stack (LASTZ1 is preserved). | E |
LASTZ1 | LASTX | Recalls LASTZ1 onto the stack. | E,(↑) |
VIEWZn | VIEW | Views the contents of Zn. Specify 0 to view LASTZ1. | N |
R | RDN | Rolls the stack down by one complex register. | E |
R | R | Rolls the stack up by one complex register. | E |
Z1 Z2 | X Y | Exchanges Z1 with Z2. | E |
Z1 Zn | CL∑ | Exchanges Z1 with Zn. Specify 0 for LASTZ1 | E |
ARC | ∑+ | ARC prefix. | N |
HYP | ∑- | HYP prefix. | N |
SIN | SIN | Sine of Z1. | E,L |
COS | COS | Cosine of Z1. | E,L |
TAN | TAN | Tangent of Z1. | E,L |
CSC | SIN-1 | Cosecant of Z1 | E,L |
SEC | COS-1 | Secant of Z1 | E,L |
COT | TAN-1 | Cotangent of Z1 | E,L |
The prefixes ARC and HYP provide a rich set of trigonometric and hyperbolic functions.
N | = | neutral stack lift status | ↑ | = | stack lifts | |
D | = | disables stack lift | ↓ | = | stack drops | |
E | = | enables stack lift | (↑) | = | stack lift if enabled | |
L | = | Z1 saved in LASTZ1 |
References
[1] | COMPLEX ARITHMETIC
Frans de Vries, May 1985 PPC Journal V12N5, page 4-9 |
|
[2] | SCIENTIFIC ANALYSIS IN THE POCKET CALCULATOR, chapter 3-8, appendix 4 Jon M. Smith, 1975 New York, John Wiley & sons |
|
[3] | LAPLACE-, FOURIER- EN Z-TRANSFORMATIE, chapter 1 Ir. A. van der Knaap, 1983 HTS Dordrecht, the Netherlands |
|
[4] | COMPLEXE REKENWIJZE OP DE STANDAARD HP41CV Coert Vonk, 1986 HP Users Nieuws #8 June 1986 pg. 24-29 |
|
[5] | MATHEMATICAL TABLES AND FORMULAS, formula 26 pg. 242 R.D. Carmichael and E.R. Smith Dover Publications Inc, New York |
|
[6] | EXTEND YOUR HP-41C, page 558
Wlodek Mier-Jedrzejowicz, 1986 Synthetix |
|
[7] | HP-41C FLAGS, PART 1 HP Key Notes V4N3, 1980 | |
[8] | COMPLEX FUNCTIONS FOR THE HP-41
Jean-Marc Baillard, 2004 see article |
|
[9] | RUNNING PRGMS IN X-MEMORY Philip Karras, April 1982 PPC Journal, V9N3, pg.26 |
Hi Coert, very nice little collection you have posted here – and world-class documentation! Thanks for sharing it…
I thought it’d be a nice idea to put all these programs in a ROM image, so you may want to use it on V41 or other hardware (Clonix, 41cl, MLDL, eproms, etc). I cannot attach it to this message bur will be glad to send it to your email address if you want.
Best wishes,
Ángel Martin
Thanks Ángel,
I posted the files through GitHub. For the URL refer to the Sources section.
There seems to be a problem with example 5.1
Calculate(2+3j)(7–6j)+(4+5j)
Answer given is 25+31j
However (2+3j)(7–6j)= 14-12j+21j-(-18)=32+9j
Then 32+9j+(4+5j)=36+14j
And this confirms on an hp prime
Excellent point Steve. I corrected the order of operators.