STO consumes stack?



#2

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.


#3

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}
ADD ; {-3-2*(s-4) 11+2*(s-4)}
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.


#4

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


#5

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.
#6

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

#7

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


#8

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.

#9

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

#10

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

#11

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


#12

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


Possibly Related Threads...
Thread Author Replies Views Last Post
  HP 50g - select characters on the stack, copy/paste Sean Freeman 7 929 11-20-2013, 07:11 AM
Last Post: Sean Freeman
  Prime: Placing more than 1 item on the RPN stack in a single program? John Colvin 4 703 11-19-2013, 08:59 AM
Last Post: Miguel Toro
  emu48 - copy stack doesn't work (as expected) Thomas Radtke 2 704 11-11-2013, 02:19 PM
Last Post: Thomas Radtke
  HP Prime Stack operations from within a program John Colvin 1 492 11-08-2013, 09:45 PM
Last Post: Helge Gabert
  Prime: Anyway to refresh stack? kris223 5 708 10-16-2013, 05:09 PM
Last Post: kris223
  hp prime - sending program results to the stack giancarlo 6 805 10-15-2013, 02:00 AM
Last Post: Giancarlo
  HP Prime - RPN stack access from programs? Mike Mander (Canada) 10 899 09-30-2013, 11:20 AM
Last Post: steindid
  WP-34S: Stack after divide by 0 Marcel Samek 4 475 08-24-2013, 11:57 PM
Last Post: Paul Dale
  HP Prime - How to STO in RPN mode? Javier Goizueta 10 893 08-18-2013, 10:24 PM
Last Post: Xavier A. (Brazil)
  Little curiosity: why the fourth stack register is called "T"? Antlab 34 2,513 07-03-2013, 04:49 PM
Last Post: Walter B

Forum Jump: