Post Reply 
Walkthrough of an RPL program for an RPN programmer
08-18-2018, 09:17 PM (This post was last modified: 08-19-2018 02:33 PM by Thomas Klemm.)
Post: #1
Walkthrough of an RPL program for an RPN programmer
(04-06-2018 11:59 AM)Maximilian Hohmann Wrote:  I would consider myself a random person in that respect (*), but I have so far failed to understand even a single program written in RPL. I don't know if I really can't understand it or if it is because I don't want to... because whenever I see anything like <<DUP ROT ... I instantly feel the urge to zap it away, just the way I would do with commercial breaks on TV or whenever a hip hop song is played on the radio.

I can give you a walkthrough of the following program for the HP-48G:
(08-18-2018 04:41 PM)Thomas Klemm Wrote:  ( mm dd yyyy -- dow )
Code:
« ROT
  IF DUP 3 <
  THEN 12 + SWAP 1 -
  ELSE SWAP
  END
  DUP 100 MOD
  SWAP 100 / IP
  → q m K J
  « { "Saturday"
      "Sunday"
      "Monday"
      "Tuesday"
      "Wednesday"
      "Thursday"
      "Friday" } 
    q
    m 1 + 2.6 * IP +
    K + K 4 / IP +
    J 4 / IP + J 2 * -
    7 MOD
    1 + GET
  »
»

To make you familiar with the context please read my original post.

Stack Commands

The aforementioned commands DUP, ROT, SWAP are well know among RPN programmers but we use different names:

DUP is ENTER but without disabling stack lift.
ROT is R↑ but for a 3-level stack.
SWAP is X<>Y.
OVER is RCL Y if you know the HP-41.
DROP is something like CLX followed by R↓.

All these commands stem from Forth so it's not something specific to RPL.

Stack Diagrams

There's an infinite stack (well not really) with RPL. This is nice: we can push stuff on it and don't have to care until later. However we don't have automatic copy of T. The stack may be empty. This is what we get with the DEL command.

You may be familiar with stack diagrams that show the state of the stack with each command.
For instance to calculate: \(3\times(4 + 5)\)

Key    X       Y       Z       T
3      3
ENTER  3       3
4      4       3
ENTER  4       4       3
5      5       4       3
+      9       3
×      27


But with Forth the order of the stack is reversed in diagrams. The top of stack is the rightmost element. But that's exactly the order you enter the data.

So on a HP-48G you can use the ENTER key to separate numbers:

3
ENTER  : 3
4
ENTER  : 3 4
5
ENTER  : 3 4 5
+      : 3 9
×      : 27


Or then you can use a space to separate numbers:

3 4 5
+      : 3 9
×      : 27


Input

( mm dd yyyy -- dow )

This is just the order we fill the stack before calling the function that returns dow, the day of week.

For today (i.e. August, 18th 2018) we would use:

8
ENTER
18
ENTER
2018


Or then:

8 18 2018


In both cases we end up with the following stack diagram:

8 18 2018


Initialisation

We have to modify the month and year in case of January and February and then calculate both the year of the century and the zero-based century.

First we bring the month mm to the top of the stack:
Code:
ROT     @ dd yyyy mm

Now we check if that value is smaller than 3.
Contrary to RPN the commands always consume the parameters even in case of comparisons.
Since we need the value later we have to duplicate it first:
Code:
IF DUP 3 <

Here are the steps in slow motion:
Code:
IF      @ dd yyyy mm
DUP     @ dd yyyy mm mm
3       @ dd yyyy mm mm 3
<       @ dd yyyy mm 0|1

The result (either 0 or 1) is then consumed by the IF statement and we branch to the correct case:
Code:
THEN 12 + SWAP 1 -

Let's split that up into multiple lines:
Code:
THEN    @ dd yyyy mm
12 +    @ dd yyyy mm+12
SWAP    @ dd mm+12 yyyy
1 -     @ dd mm+12 yyyy-1

The other case is much simpler:
Code:
ELSE    @ dd yyyy mm
SWAP    @ dd mm yyyy

And then we finish the IF statement with:
Code:
END

We just have to make sure that at the end of both branches the order of the elements is the same.

year of the century

For this we just have to calculate: yyyy MOD 100.
But since we need that value again later we better make a copy beforehand:
Code:
DUP     @ dd mm YYyy YYyy
100     @ dd mm YYyy YYyy 100
MOD     @ dd mm YYyy yy

zero-based century

We take the integer part of yyyy after dividing it by 100:
Code:
SWAP    @ dd mm yy YYyy
100     @ dd mm yy YYyy 100
/       @ dd mm yy YY.yy
IP      @ dd mm yy YY

Local Variables

The next line creates a new context for local variables.
They are assigned in the same order that they appear on the stack.

Code:
  → q m K J

Thus we end up with:

q = dd
m = mm
K = yy
J = YY


The context is marked with these guillemets:
Code:
«

»

This step consumed the stack completely so it's now empty.

List of Weekdays

We push that list now but we need it only later:
Code:
{ "Saturday"
"Sunday"
"Monday"
"Tuesday"
"Wednesday"
"Thursday"
"Friday" }

Calculating the Zeller's congruence

The next steps should be easy to understand since it's exactly how you'd calculate the expression on any RPN calculator:

\(h=\left(q+\left\lfloor {\frac {13(m+1)}{5}}\right\rfloor +K+\left\lfloor {\frac {K}{4}}\right\rfloor +\left\lfloor {\frac {J}{4}}\right\rfloor -2J\right){\bmod {7}}\)

Code:
q
m 1 + 2.6 * IP +
K + 
K 4 / IP +
J 4 / IP + 
J 2 * -
7 MOD

This leaves us with the following stack diagram:

weekdays h


Mapping to Day of Week

Since the index of lists start with 1 we have to adjust that:
Code:
1 + GET

I assume that you can figure out by yourself what GET does.

Next Steps

Debugger

I highly recommend to run the program in the debugger and single step through it. So you can follow the changes of the stack with each step.

Control Structures

There are other control structures that you could explore: CASE, START, FOR, DO, WHILE

List Operations

There's a good reason this language has Lisp in it's acronym. It's worth to make you familiar with lists and their powerful operations.

It allows to calculate Gauss's shoelace formula with just a few lines:
Code:
«
  DUP HEAD +
  2 « CROSS » DOSUBS
  ∑LIST ABS 2 /
»

Kind regards
Thomas
Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
Walkthrough of an RPL program for an RPN programmer - Thomas Klemm - 08-18-2018 09:17 PM



User(s) browsing this thread: 1 Guest(s)