Show Me the Code!
In this article, we will show how to enter this right triangle solver program on an R47:
LBL 'Tri' ; find missing value STOred in Z² + Y² = X² or Z² = X² - Y²
x≠0? ; hypotenuse given in X?
GTO l ; yes; find the leg
+ ; DROP zero hypotenuse
LBL 'Hyp' ; find that missing hypotenuse
x² ; T Z Y X²
x⇋y ; T Z X² Y
LBL h ; lets l bypass initial Hyp steps
x² ; T Z X² Y²
+ ; T T Z X²+Y²
√x ; T T Z answer
RTN
LBL l ; rearrange stack to calculate the missing leg's length
R↓ ; send nonzero hypotenuse in X up to T
+ ; correct call requires Z or Y to be 0 when X is nonzero
x²
CHS ; key calculation difference amounts to "add the negative"
R↑ ; bring hypotenuse back down into X
GTO h ; hijack "find the hypotenuse" method as "find the leg”
END
Along the way, we will explain what it does and why it was designed this way.
The intent is that you enter it by following this guide, but if you just want the code, it may be downloaded here.
For commentary on why this example is formatted as it is, see my companion article, Program Style.
Programming Mode
Press 🟧 PRGM to begin entering a program.
You may see the acronym PEM elsewhere, especially in the R47 reference documentation and the calculator source code, but we will not use that here. This tutorial is intended for end users who will see PRGM printed in orange on the faceplate, and so we deem that low-level internal acronym unhelpful up here at our level. I mention it here for two reasons. First, you might re-encounter it and recall having seen it explained here. Second, you might be searching this wiki trying to find out what the heck “PEM” means in the R47 context. Now you know.
We presume this to be our first tentative step into this world, where we start with a blank slate. If that is not the case, you have several choices:
- Use the
⬆︎/⬇︎keys to position the cursor above an existingLBLto add your new program ahead of it. - 🟦
GTO..to position the program input point ahead of all preexisting programs. - 🟦
CLR🟦DELETEDELPorDELPallto erase some or all preexisting programs; destructive! - 🟦
CLR🟦RESETto erase the calculator’s memory and return it to its default state; nuke-and-pave!
The overarching goal here is to avoid is entering our new program in the middle of another, wrecking it.
Alpha Mode and Our First Global Label
Unlike on most older programmable HP calculators, there is no dedicated LBL button or shifted function with which to label our program. Instead, entering PRGM mode brings up one of the R47’s many, many menus. The first item in the lowest level of the on-screen menu in programming mode is LBL, so press the first soft menu key, sometimes called F1 for lack of a printed legend.
You should now see “LBL __” at the input location, plus a new menu suggesting possible labels for this new program. None of its single-letter offerings appeal to us, so press 🟧 𝒂 to begin entering an alphabetic label. Three separate user interface changes signal the mode change:
- An opening single quote mark appears in the input field.
- A new menu replaces the selections given on starting the
LBLinstruction. - Up on the top line, near the right side, either “A” or “a” appears depending on the state of the
CAPSmenu toggle you see in the upper left corner of the new menu.
The standard English alphabet is printed in white on the faceplate, to the right of the keys that produce each letter in this mode. The R47 has a far larger alphabet than this, but this will suffice for our purposes here.
Step-by-step, the input sequence is:
- toggle
CAPSon if it was not already enabled - enter the leading “T” by pressing the
6key - toggle
CAPSoff - enter the lowercase “ri” with
4thenR↓ - hit
ENTERto complete the label
Because we entered this label in 🟧 𝒂 mode, it will be visible in lists of programs. One way to pull this up is to hit the XEQ button, then choose the PROG sub-menu. Another is to hit 🟧 CAT and choose PROGS.
This declares the program’s primary entry point, Tri, taking 3 parameters from the stack, entered in this order:
- Z: leg 1
- Y: leg 2
- X: hypotenuse
The intent is that one of the three should be 0, marking the side to solve for, given the other two.
Keyboard Entry Mode
For those who have never encountered it before, the calculator programming mode we use here is called “keyboard-entry” because on the older HP calculators, it was merely a recording of a sequence of keypresses, stored as an ordered list of instructions that could be repeated on demand. That began to change in the 40-series RPN evolutionary line emulated by the R47, plus the parallel RPL line. Especially in the R47, the large number of possible functions visible only via the menus, not available as keypresses per se beggars the old “keyboard-entry” characterization, yet the basic operating principle remains.
I point that out here because our next instruction — x≠0? — is not a dedicated button as it was on, say, the HP-11C. It is instead composed using this sequence:
- 🟧
F6to open theTESTmenu from the mainP.FNmenu, which you should return to after exiting 🟧𝒂mode above. F4to selectx≠ ?— not to be confused with the specialized variants in 🟧F1andF2- input the 0 comparison value in any of several ways:
000ENTER0.- 🟧
F1to select the predefined0.option
Notice that all are two keystrokes, leaving us without a strong, objective reason to prefer any of these options. My weakly-held preference is for the first, since I can enter it with a single key, repeated.
The HP programming model emulated by the R47 employs a “do if true” scheme where a true result of a test like this one causes the next instruction to be executed, but when the test is false, that instruction is instead skipped. By far the most common instruction to use following a test is a GTO, as we see here.
Local Labels
I chose to name the referenced subroutine with a lowercase “L” for a bunch of intertwined reasons:
- It is mnemonic for the right triangle’s “leg length” which is what we compute via this path.
- Single letter labels
a-lgiven outside alpha quotes will not show up in lists of available functions, which we desire since this subroutine is not meant to be called from the outside. - The
A-Lrange is also local, allowingLto avoid the visual confusion with the digit1, but lowercase feels more “local” to me. - Numeric labels are also local in the R47, but I prefer not to use them in a calculator this powerful; they feel like a throwback to the pre-
𝒂world.
We will put off defining this l subroutine for now. Unlike other programming languages which are strict about the ordering of definitions and references to same, the HP programming model allows free-form declaration. A go-to statement (GTO) causes the calculator to scan forward until it finds the LBL, looping around to the top of the program if it hits the END statement first. While this design does permit duplicate labels within a single program, relying on this implementation detail is bad practice.
Notice that we indent subroutines beginning with local labels in the presentation above. The calculator proper does not do this, but we show it that way to indicate which labels are visible at global scope and which are not.
A Second Global Routine
This program has a second entry-point called Hyp for calculating the hypotenuse of a right triangle, without going through the more general-purpose Tri interface. It is used internally, but we give it an alpha name to allow it to be called directly by the user. This is a nice feature since it has a simpler calling interface, taking the lengths of the legs in X and Y.
Return (RTN)
Until we get to the RTN call several lines down from that GTO l call, each subsequent step is entered from the keyboard using methods you already know. Do that now.
Like LBL, the RTN function on the R47 is not a dedicated key but an item on the P.FN menu you should still have up from before.
This returns control from a program to the caller, which may either be an XEQ call from the keyboard or a GSB from another part of the program. This is often at the end of a program, but here we do it from the middle because there are further subroutines after this, and so we need a way to say, “We’re done at this point. Do not continue executing the code.”
The END
Nearly everything else that follows is straightforward. Enter it as shown.
The sole remaining surprise for newbies to the HP-41 evolutionary line in HP programming is the END statement, which tells the R47 where one logical program ends and the next begins.
Earlier HP designs did not require this because everything shared a single global namespace. We saw in this program two LBL statements with a single lowercase letter, being local labels, and it is in support of them that the R47 programming model requires this explicit END marker.
Design Decisions
Even in a short — nearly trivial — program like this one, we find room for deliberative design.
We have already covered most of the reasoning behind why this program is written as it is, but a few details worth discussing remain.
You may have previously read my Hypotenuse Program for the HP-32S and recognize the basic structure of this program from the combined solver presented at the end of that article. Yet, despite broad similarities in the many flavors of the HP keyboard-entry programming model, there is enough variance to prevent direct porting at the high-level instruction level, much less allow binary compatibility. The 32S and the 42S came out in the same year, but they represent different evolutionary lines, which affects how each is best programmed even in cases where an identical instruction sequence would technically work.
One big difference is that the 32S version expects its parameters to be STO’d in global variables A, B, and C. I could not do that on the R47 because without quotes, those refer to registers assigned to the 8-level stack in the default SSIZE8 mode, and I did not want to require that the user switch to SSIZE4 mode merely to free these three registers up for general-purpose use. Better to change the calling convention to match the nature of the R47’s programming model.
One alternative I tried but later rejected was to have the user pass the parameters in the global variables in ’a’ thru ’c’ instead. The problem here is that unlike registers, one cannot RCL an undefined variable and get the zero I wanted. Since I was not willing to add a bunch of code to do conditional RCL testing to prevent the calculator from complaining about undefined variables, I chose to switch the calling convention to use the stack instead of named variables. A more idiomatic 40-series alternative is to call INPUT, but I did not want to get into that in this initial tutorial.
(You may now wish to return to my R47 article index.)
License
This work is © 2025-2026 by Warren Young and is licensed under CC BY-NC-SA 4.0