The Museum of HP Calculators

HP Forum Archive 18

 STO consumes stack?Message #1 Posted by MikeO on 24 Aug 2008, 4:39 p.m. OK, This has been bugging me for awhile. I jumped from the HP41C era to the HP50g overnight, so forgive me if this question comes about 20 years too late (when the HP28C arrived): Why in heck would STO consume a stack entry? On the HP41, or any RPN calculator prior to that, an STO simply stores the current value in the X register - leaving the value there without disturbing the stack. You are then able to continue a calculation with that value without further trouble. On the RPL calculators, it seems that RPN has been taken to its extreme: STO is treated like any other operation, and consumes the "argument" (value) on the stack when it stores the value. So, if I want to continue using that value in my calculation, I have to retrieve it somehow. The easiest way being to DUP the current value before STOing it - an extra operation/keystroke. Is there a good explanation of why this is better than the old way? Perhaps the STO operation should have been treated exactly as a function, having it return the passed in argument value as a return value? -MikeO Edited: 24 Aug 2008, 5:01 p.m.

Re: STO consumes stack?
Message #2 Posted by Allen on 24 Aug 2008, 5:40 p.m.,
in response to message #1 by MikeO

The only reason I can think to use a STO in the middle of a program is to save a small snapshot of one of the stack registers for later recall or testing.

I can't speak categorically, but there are over a dozen Stack operations on the Charlemagne Series (not including the SysRPL variants). With RPL's extreme stack agility and a near limitless stack depth, there is a much smaller motivation to store intermediate values during calculation.

You can see a good example of a moderately complex program in both RPL and RPN: in Ulam Spiral Mini Challenge

## RPL Version

Note the use of Stack Commands DUP, SWAP. Counters are handled internally by loop commands. Input variable stored with "->" command. Program outputs kept and output to stack.
```Bytes: 255
Checksum:#64353d
Variables used: 1 Local, 0 Global
Flags used: 01
<< 1 CF -> N ; set up FLAG1 as odd/even increment for Floor/Ceil loop
<< 2 2            ; This skips 1 and 2 as input ( see assumptions)
DO DUP SQRT 1     ; Main loop to determine the corners (7,10,13,17,21...)
IF FS?            ; Test for first or second corner between
THEN CIEL 1 CF    ; perfect squares.
ELSE FLOOR 1 SF   ; Corner numbers are alternate
END               ; cv2=cv1+floor(sqrt(cv1))  OR
+                 ; cv2=cv1+ ceil(sqrt(cv1))
SWAP 1 + SWAP     ; increment corner counter
UNTIL DUP N >=    ; Stop if you are at the corner or side
END               ; gives side number(s) and corner value
IF DUP N ==       ; if the input IS the corner number
THEN SWAP 2 * 3 + ; use corner formula
DUP 2 + ->LIST    ; {2*s+3 2*s+5}
ELSE SWAP 4 -     ; else use side formula:
{-2 2} * {-3 11}
END
{-1 1} +           ; All solutions have N+1 and N-1
DUP DUP / N * ADD  ; Adding N to all list values {-1 1 s1 s2)
SWAP DROP SORT     ; Clean stack and sort
>>
>>
```

## Unoptimized RPN solution

Note use of STO as counter for variables 01, 02, and to Keep intermediate values of 07 and 08 (program outputs).
```bytes: 76
Flags:     01- Used for corners of form x^2+1
Registers:  00- I nput number
01- C orner counter value
02- N ext corner value
07- L ow solution difference
08- H igh solution difference

00 { 76-Byte Prgm }
01>LBL 00     ; program label, Program init.
02 CF 01      ; use flag 01 again for alternating loop
03 STO 00     ;
04 2
05 STO 01
06 STO 02     ; initial conditions C=2 and N=2
07>LBL 01     ; Loop to find the next highest corner value
08 1          ; and corner count
09 STO+ 01    ; increment corner value in loop
10 RCL 02
11 SQRT
12 IP
13 STO+ 02    ; add floor(sqrt(N)) to N
14 CLX        ; place 0 on stack w/o push
15 FS? 01
16 1
17 STO+ 02    ; make ceil(sqrt(N)) if near x^2
18 FC?C 01
19 SF 01      ; Toggle Flag 01
20 RCL 02
21 RCL 00
22 X>Y?       ; Test for the side,
23 GTO 01     ; repeat addition if too low
24 X=Y?       ;  Test for the corner
25 GTO 02     ; If yes, use corner algorithm
26 RCL 01     ; Otherwise use side algorithm
27 4
28 -
29 2
30 *
31 3
32 +
33 +/-
34 STO 07     ; L= -3-2*(C-4)
35 +/-
36 8
37 +
38 STO 08     ; (new) H=-L+8
39 GTO 03     ; Report results
40>LBL 02     ; Corner algorithm
41 RCL 01
42 2
43 *
44 3
45 +
46 STO 07     ;L=3+2*c
47 2
48 +
49 STO 08     ;H=L+2
50>LBL 03     ;Report results
51 RCL 07
52 RCL 00
53 +         ;Y=I+L
54 RCL 08
55 RCL 00
56 +         ;X=I+H
57 .END.
```

 Re: STO consumes stack?Message #3 Posted by Karl Schneider on 24 Aug 2008, 10:49 p.m.,in response to message #2 by Allen Hi, Allen -- Good program comparison. I'd say that "CIEL" should read, "CEIL". The RPN program reads sort of like an assembly routine, but I can follow the steps. My brain just doesn't work in the manner required to understand RPL very well. -- KS

 Re: STO consumes stack?Message #4 Posted by Walter B on 25 Aug 2008, 1:38 a.m.,in response to message #3 by Karl Schneider Quote: The RPN program reads sort of like an assembly routine, but I can follow the steps. My brain just doesn't work in the manner required to understand RPL very well. Nor does mine. IMHO RPL is an example for a principle (here: postfix notation) overstressed.

 Re: STO consumes stack?Message #5 Posted by MikeO on 25 Aug 2008, 12:04 a.m.,in response to message #2 by Allen I have to admit that I find the RPN version easier to follow. The DUPs sprinkled throughout the RPL program don't add much to its readability - but, that's because I haven't spent a lot of time programming RPL yet. I suspect the reason there are so many DUPs in the RPL is because, in most cases, the programmer wants to retain these values after they are tested logically - which was part of my point. I'll concede that STO is probably less needed with an infinite stack - as long as you are willing to track offsets (like assembler subroutines do), but STO, along with conditional tests, as long as you are using them, shouldn't really consume their arguments. I think it's a bit inefficient to be DUPing things all the time. Of course, this is so ingrained in the current RPL language usage, it will not do to change things at this point! -Mike O

 Re: STO consumes stack?Message #6 Posted by Steve Simpkin on 24 Aug 2008, 8:29 p.m.,in response to message #1 by MikeO In his book, "HP41/HP48 Transitions", William C. Wickes describes differences between the HP41 and the HP48 calculators as well as the concept of Stack Housekeeping. Here are a few quotes concerning the operation of the STO operation. "But it may be a little disconcerting the first time you use STO on the HP48, to see the object you just stored disappear from the stack -- especially by contrast with the HP 41 STO, which leaves a copy of the of the stored object on the stack." "If commands did not remove their arguments from the stack, you would have to take the trouble to drop them when you no longer need them." "When you use STO to preserve an intermediate result in the middle of a calculation, you may prefer to keep the result on the stack so that you can continue the calculation. In this case, just execute DUP (press ENTER if you're working from the keyboard) before you enter the variable name for the STO. If you forget, the stored object is always available by name in the VAR menu." Although this book is out of print, I highly recommend it for anyone transitioning from the HP41 to the HP48/49/50 series calculators. You can often see a copy on eBay or if an electronic form is OK, you can get a copy from the HP Museum CD/DVD set. See:HP Museum CD/DVD Offer

 Re: STO consumes stack?Message #7 Posted by Allen on 24 Aug 2008, 8:33 p.m.,in response to message #6 by Steve Simpkin I agree. Wickes books are among my favorite reads. The transitions books are hard to find, but worth the trouble! There is also a HP 48 Insights series that has great into to RPL, including good/better/best examples of refining programs. Well written- hope to meet the author some day and offer my complements in person.

 Re: STO consumes stack?Message #8 Posted by MikeO on 24 Aug 2008, 11:25 p.m.,in response to message #6 by Steve Simpkin Thank you Steve. I just got the museum DVD. I will look for the book there and give it a read. One other item that struck me was the fact that conditional tests also consume their arguments. Again, I need to remember to arrange values on the stack and DUPing to avoid losing them. From my experience with machine language and stack frames, I'm familiar with using an offset to refer to working variables on a stack. Thanks for the reference. -MikeO

 Re: STO consumes stack?Message #9 Posted by Kiyoshi Akima on 25 Aug 2008, 5:33 p.m.,in response to message #6 by Steve Simpkin Quote: "If commands did not remove their arguments from the stack, you would have to take the trouble to drop them when you no longer need them." I just took a quick look through my current project (a bunch of general-purpose programs for multiple integration). In five programs totalling about 2400 bytes, there were eight STOs (including three that really are STO+), a much smaller number than there would be in similar RPN programs. Exactly zero of them had a preceding DUP to preserve the value on the stack. Three programs for one-dimensional adaptive quadrature totalling about 1900 bytes had zero STO operations. This completely unscientific survey shows that programs on the average would be 2.5 bytes longer if STO didn't remove the argument from the stack. Though it's possible I'm now familiar enough with RPL to have organized the stack taking advantage of STO removing its arguments. I haven't spent much time optimizing any of these programs. In my experience I've found that optimization tends to remove STOs, keeping more intermediate values on the stack. In a 2000 byte SysRPL Enigma emulator, I have thirteen PUTLAMs, only four of which have some form of DUP preceding them. Your mileage will most likely vary. ka

 Re: STO consumes stack?Message #10 Posted by Karl Schneider on 24 Aug 2008, 10:44 p.m.,in response to message #1 by MikeO Hi, "Mike O" -- Yes indeed, that's the crux of the RPN vs. RPL philosophical arguments. Quote: Why in heck would STO consume a stack entry? ... STO is treated like any other operation, and consumes the "argument" (value) on the stack when it stores the value. The previous replies were good and informative, but the heart of the matter is simple: RPL is rigorously consistent in that every command is postfix, requiring input "arguments" to be provided beforehand on the stack -- even when those inputs are merely values of settings (e.g., 5 FIX), and not bona fide numerical operands. Input arguments are always consumed, because if they weren't, they would enlarge the dynamic RPL stack with unneeded or unwanted detritus, slowing processing time and interfering with stack manipulation. This is not an issue with RPN, because such detritus will ultimately get pushed off the top of the fixed 4-level stack. It is the user's responsibility to ensure that wanted data does not get pushed off... -- KS Edited: 24 Aug 2008, 10:53 p.m. after one or more responses were posted

 Re: STO consumes stack?Message #11 Posted by Paul Dale on 24 Aug 2008, 10:51 p.m.,in response to message #10 by Karl Schneider Quote:RPL is rigorously consistent in that every command is postfix, requiring input "arguments" to be provided beforehand on the stack -- even when those inputs are merely setting values, and not numerical operands. Well almost every. FOR has the loop variable after the keyword not on the stack. Also, -> (right arrow) has the variable list and the program to execute after. And yes I understand why these are so. - Pauli

Go back to the main exhibit hall