Enter RPN

R47: The HP-16C Superset
Login

R47: The HP-16C Superset

Motivation

Hewlett-Packard Model HP-16C Progammable RPN Calculator, HP's First and Only Calculator for programmers

The HP-16C was a curious beast. Discontinued in 1989 without any clear successor, working copies in clean condition remain sufficiently sought-after that they can command the price of a brand-new R47. In large part, this is because until relatively recently, the options for off-the-shelf handheld calculators that could do everything the 16C could were sparse, particularly if you required proper RPN support to go with it. You could find quite a few options if you were willing to accept a purely software offering, but that left you no handheld option short of a smartphone. Alternatives requiring the conversion of another calculator also existed, which I found dissatisfying to varying degrees.

Prior to receiving the R47, my go-to was PCalc, which isn’t all that much like an HP despite offering a high-quality RPN mode. PCalc is nevertheless a fine example of the art; the very name is short for “programmer’s calculator,” which is the very same purpose the 16C was designed to serve. HP chose to dub their offering the “Computer Scientist,” but like PCalc, it falls very much on the practitioner’s side of the line, not the theoretical. The closest an actual computer scientist was likely to get in 1982 to a serious dive into bitwise manipulations was to write a treatise on discrete mathematics.

The problem with developing expensive tools aimed at this particular set of working practitioners is that they are the cadre least in need of third-party assistance. I count myself among them, and we programmers have a long history of building our own tools even when they’re available for less money than we’d spend to recreate them, all costs considered.

Why? Those who do not enjoy programming give it up fairly quickly. Put a problem in front of us that is solvable by writing a program but offer a way to buy the same tool for a fraction of the development cost, and some programmer somewhere with a proper avocation for the work will go “Nah, thanks, I’ll write my own,” then put it out as FOSS, instantly undermining the market for that commercial tool. The first free version will typically be far less capable than the one driven forward by a bunch of venture fund suits insisting that there truly is such a thing as a too-low R&D burn rate. Yet, the moment there is a free version available in source code form, other programmers will pick it up, notice the bugs and missing features, then begin enhancing it bit by bit. The more developers who do this, the better the tool gets, so the more developers it attracts, and ’round it goes.

There are faster ways to lose millions of dollars than starting a company making tools for programmers, but most of the others are illegal. 🤓

Doubt me? Go ask a Borland, MetroWerks, THINK, Watcom, or Zortech alum about the pucker they felt on realizing that every C toolchain is suddenly based on GCC. Then dig back a step and ask the commercial Unix vendors what happened to the revenue from their extra-cost development tool lines after the Linux movement got its feet under it. This same set of forces is why Apple did not even try to commercialize Clang after hiring its lead developer; they knew the alternatives available to them were FOSS or failure.

This at last brings me to the reason we finally have a credible HP-16C successor in the R47: a felicitous alignment of incentives. Starting with the HP 30/20b and then echoed by SwissMicros with their DMCP SDKs, these calculator manufacturers’ wise decision to make their hardware platforms open to modification allowed a self-selecting few to make their own tools, to the wider benefit of the community. The R47 traces its lineage back to the ancestral WP34s project in this manner, and it is from this base that much of the following ultimately derives.

While the R47 is not a strict superset of the HP-16C, there are good reasons for each exception. The bulk of this functionality is split across the 🟧 BASE and 🟧 BITS menus, but in order to keep these 2-page menus from spilling over to a third,1 the rest is in the neighboring 🟧 INTS menu.

With that grounding, we can get down to shiftin’ them bits.

But first…

Why Not Use a REPL?

Many programming languages offer a REPL where expressions can be tried interactively, much as on a calculator. If I want to know how the Python setup installed on a given machine evaluates something, I can type python3 in my Terminal window and input my expression after the >>> prompt, then hit Enter. Done! What do I need a dedicated programmer’s calculator for?

One reason might be that you’re using a language like C, which lacks a widely used REPL. Whereas I might begin probing the 32-bit integer overflow behavior of Python by typing 2**32 at its REPL, if my interest happens to be in how C does it instead, I have to type in all this…

#include <math.h>
#include <stdio.h>
#include <stdint.h>

int main(void)
{
    printf("%llu\n", (uint64_t)pow(2, 32));
    return 0;
}

…then compile and run that program to get my answer.

More, I have to do that each time I have a question about how a given programming language, compiler, math library, and CPU combine to interpret a given expression. That’s an awfully heavyweight Q&A process.

Easing that burden is the original purpose for tools like the HP-16C. Especially in 1982 when the costs of the above method were much higher, dragging a calculator across the desk and punching in the expression was much faster provided one could match the target machine’s behavior with sufficient fidelity to make the answer meaningful.

And that’s the primary sticking point, the one that separates the professional from the perfunctory.

Computer Representation of Numbers

Just as humans have come up with many different ways to write numbers, our species has found itself unable to settle on a single way of representing numbers in computers and calculators. Because these machines so often get optimized down to the cheapest thing that can possibly work, those of us tasked with calculating within these limits run into the edge cases more often than those in other STEM fields. The R47’s vast real and long integer data types tend to make limitations a matter of distant concern, but for computer math, we find value in the R47’s purposefully constrained short integer data type for making confident predictions of how our programs’ calculations will come out.

The Word Size Problem

Starting with the personal computer craze in the late 1970s, we cranked the Moore’s Law Business Rule handle several times and soon found that even cheap handhelds aimed at high-schoolers gained the four primary base conversions at the least: binary, octal, decimal, and hexadecimal. There do exist scientific calculators made since this revolution that lack even a pretense toward serving programmers, but they’re typically an extreme case: small entry-level school calculators, bargain aisle jobbies, and so forth.

We could go into a whole lot of compare-and-contrast at this point, but let us instead go straight to the sharpest knife in the drawer, the one most likely to make the incisive discrimination: customizable word sizes.

First, recall our problem above, probing into the behavior of integer rollover for 32-bit words. The Python and C examples above tell us we’re likely working with a 64-bit machine, because if it was a 32-bit system, it would have either thrown an overflow error or hidden the problem by returning all-zeroes, depending on how much hand-holding was built into the system.

Yet this is a false dichotomy.

Perhaps the easiest way to see why is to pull out any scientific calculator in HP’s Pioneer series.2 What we will do next was tested on an HP-20S, an HP-32S, and an emulator for the HP-42S. If you do not have one of these at hand, you could go download a copy of that same emulator — either Free42 or its bigger brother Plus42 — to demonstrate the following symptom:

  1. Put in 232 using the regular decimal calculation mode, then convert it to hexadecimal, yielding 1 0000 000016.

  2. We hypothesize that this means the calculator is using 64-bit integer arithmetic. Probe this by multiplying the value by 2.

    2 0000 000016, right? Good!

  3. Okay, let’s multiply by 2 again; 4 0000 000016. Our presumption continues holding up so far.

  4. But now do it once again.

Oops! What happened? The details depend on the machine:

Why? What’s going on? These machines clearly go beyond 32-bit words, yet they fail well before the 64-bit limit.

All three designs are based on the HP proprietary Saturn CPU, which is nibble-based, allowing it to most easily handle things in groups of four bits. The primary reason for that design choice is to simplify BCD arithmetic handling, but the knock-on effect we see here is that in order to handle the largest computer integers commonly in use at the time — 32-bit unsigned — on calculators designed primarily to handle signed real numbers, they had to step up to the next nibble. Had they not, entering FFFF FFFF16 would give a confusing result.

Yes, that does mean these machines do everything related to hexadecimal arithmetic with 36-bit signed integers! The clamped value we see above is 7 FFFF FFFF16 = 235-1.

How, then, can we expect one of these Pioneers to properly model a given 32-bit ALU, that we may come to confident conclusions of how it will operate without needing to write a program and run it on that hardware to test our hypotheses?

And how, these many decades later, can we get these classic old calculators to support modern 64-bit words?

Answer: we shouldn’t, and we can’t.

Custom Word Sizes to the Rescue

The first step toward a proper solution is using a calculator that allows us to set the word size of the machine we are trying to get it to emulate.

(That, or write software that runs on the device in question using native CPU arithmetic, but remember, we’re trying to get away from that.)

There are presets for this on the first page of the R47’s 🟧 BASE menu for the common 8, 16, 32, and 64-bit word sizes. Arbitrary word size options are available as well, which we will get to shortly.

Thus why the HP-16C remains sought-after as more than a mere museum piece: a 64-bit limit was positively enormous back in 1982 when the 16C was first released. Even today as I write this, the address buses of the “64-bit” CPUs inside the computing devices my readers are likely reading this article on will be limited to somewhere between 39 and 48 bits. That upper limit will last us a long time, sufficing until we have machines with more than 256 TiB of RAM.

And how did I come to that number? With an R47, of course!

🟧 DISP UNIT 3
🟧 PREF CFLG 1024ⁿ▣
2 ENTER 48. yˣ

(The decimal in the last line is important, but it can go on the 2 instead, if you prefer. Without it, you will require an integer to real conversion step to force UNIT mode to take effect here.)

Covering All the Edge Cases

Although power-of-2 word sizes — 8, 16, 32, 64… — have predominated since the mid-1970s, they are not universal. Sizes divisible by 3 were surprisingly common before the 8-bit byte solidified into a de facto standard.3 The best example of this I’m aware of is the DEC PDP-8, a machine with 12-bit words plus 3-bit IF/DF registers for selecting the instruction and data fields, respectively, each being a separate 12-bit 4 kWord address space. This gives us 15-bit segmented access to 32 kWords of memory.4

One solid setup for emulating PDP-8 integer arithmetic on an R47 is:

🟧 BASE OCT
⬆︎ 🟧 BITSET
🟧 WSIZE 15

We could just as well choose 03 or 12, depending on what we’re trying to accomplish. The important bit is that even though such atypical settings have sparse application these days, they continue to have true utility, and not merely in the context of a dusty computer museum warehouse. There do in fact exist featureful PDP-8 clones on the market, much as we have HP RPN calculator reproductions. This then explains why the BASE menu continues to offer the octal display mode as a top-tier option even though it is easily the least commonly used: it is convenient for these cases because 2³=8.

I could list many other edge cases like this, but I will restrict myself to one of significantly more recent vintage: the tricksy data formats used to save GPU memory and AI model download time while giving many of the advantages of standard 32-bit IEEE 754 single-precision floats.

Whatever your use case, the R47 likely has it covered.

It should be noted that the 🟧 BITSET 🟧 WSIZE setting allows any word size from 1 to 64 even though there is a 32-bit microcontroller5 at the R47’s heart. This underlying silicon limitation does not affect the R47 because it does all critical math in software.

Double-Word Arithmetic

A related set of features are the HP-16C’s double-word integer arithmetic operators, given as 🟦-shifted functions on its ÷, ×, and 9 keys. The R47 supports all three over on the 🟧 INTS menu. (Some of that spillover we mentioned above.)

DBL× is the most useful, employed when your number format is too short to handle a multiplication without overflowing.

It is a provable property of integer multiplication that the result cannot be any larger than the sum of the multiplicands’ word sizes:

`Let: 0 ≤ A < 2^m and 0 ≤ B < 2^n; then: A×B < 2^m × 2^n = 2^(m+n)`

Two 32-bit numbers cannot multiply to a result larger than 64 bits, for instance.

This mode takes advantage of that, multiplying normally while putting the result’s most significant bits into Y and the least significant in X. In principle, this can allow a 128-bit integer result on an HP-16C, so long as you’re willing to do the side-scrolling and x⇋y swapping needed to read it out.

The double-word division operation DBL÷6 divides X into the double-word value in {Z, Y} and puts the result into X. Be careful with this! The same property of numbers referenced above does not guarantee that the result fits into a single word; trivial example, X=1. The presumption is that you are doing a substantial division here, as with inverting a prior DBL×.

That leaves DBLR, the double-word version of the remainder operation, being a rather trivial variation on double-word divide.

How useful all this is on a machine with a 1000-digit long integer data type I leave to your own evaluation. I will go this far: double-word arithmetic is far easier to get your head around on a machine that shows 2-4 stack levels at once, depending on the mode, as compared to the HP-16C’s single-line 7-segment LCD.

Remainders (When you absolutely, positively cannot have fractional parts)

The HP-16C was primarily an integer calculating machine, and so we should not be surprised at the answer this gets us:

DEC 5 ENTER 3 ÷

Yup, one, not 1.6̅, and certainly not `1 2/5`.

While the link above gives an alternative, it would be more in the idiom to ask instead:

5 ENTER 3 🟧 RMD

We get 2, the integer remainder of dividing 3 into 5.

To the best of my knowledge, the first time that appeared on a normal HP scientific calculator was the high-end HP-42S. It never made it down the line until Kinpo Electronics added it to the HP 33s as the f INGT Rmdr feature. It’s too bad; if all you want to know is whether one number divides evenly into another, it’s cheaper to compute than a real-number division followed by a call to FP for checking against 0.

The R47 not only gives us RMD on the default Home menu accessed by long-pressing 🟧, we also get MOD7 and IDIV as neighbors, being closely related functions: integer division and the remainder of same.

Their permanent home is on 🟧 INTS, where we also find ×MOD and ^MOD. What do these do, now? These are triadic operations. The first computes Z×Y before giving the result modulo X, while the second computes ZY first. These are primitives in modular arithmetic, used in domains like cryptography. Divisions are rarely useful in these types of applications, and overflow prediction for additions/subtractions are easy enough to manage without the aid of special functions.

Signedness

HP’s choice in the Saturn CPU to use 36-bit signed arithmetic to cover the 32-bit unsigned use case is unsatisfying on both practical and aesthetic grounds. If we’re dealing with unsigned values in our programs and are trying to model this behavior using the programmer’s calculator we keep within reach, we bloody well want unsigned arithmetic! It matters.

The fast path to setting this up on the R47 is to use the presets on the second page of the 🟧 BASE menu: U64 sets its short integer data type to 64-bit unsigned mode, while S08 sets it for signed 8-bit integers.

There are good reasons for wanting to change the signedness independently of the word size, but for this you have to dig one menu deeper: 🟧 BASE ⬇︎ 🟧 BITSET. There are seven related but mutually-exclusive options here:

The HP-16C provides only the first three modes. Already the R47 has pressed far ahead.

One reason that nearly every computer since the mid-1960s has used two’s complement is that this representation does not allow the silly distinction between positive and negative zero. The concomitant cost is that this representation is not symmetric about zero. I bring that up here because it explains the existence of 🟧 PRGM 🟧 TEST x=-0? and its immediate neighbor x=+0? on the same menu as the more straightforward and historically common x=0?

The Status Bar Annunciator

These prior two sections at last allow us to understand the meaning of the 64:2 in the R47’s status bar, in the default setup: 64-bit two’s complement signed short integers, likely the preferred format of the computer you are reading this on. Calling the U32 preset changes this to 32:u for instance.

Work is planned to unify these two notations, but as of this writing, it remains a wish-list item.

Bitwise Manipulations

Now that we have sorted out all our numeric representation issues, we can begin using the calculator to model a given ALU’s behavior. We will start with bit twiddling for roughly the same reason we tackled the word size difficulties first, above: calculators with pretensions toward serving the working software developer tend to provide an underwhelming bitwise arithmetic feature set compared to our paragon, the HP-16C, and the rest leave this functionality out entirely.

You will be unsurprised to learn that the R47 is in a different class from these wannabes.

Bit Shifting and Rotating

The HP-16C provides:

…plus assorted variations.

The distinction between shifting and rotating comes down to what happens to the bits pushed off the end of the word:

Shifting

With shifting, the top or bottom-most bit is shifted into the calculator’s carry flag at each step, overwriting the prior value. Thus with a 2-place left shift, the second-to-topmost bit ends up in the carry flag, and the prior top bit is lost.

Given an 8-bit unsigned word size (🟧 BASE ⬆︎ 🟦 U08) and 101011112 in X

C 1 0 1 0 1 1 1 1
box "C" width 0.15 height 0.2

move previous.width

box "1" width previous.width height previous.height
box "0" same
box "1" same
box "0" same

move previous.width / 2

box "1" same
box "1" same
box "1" same
box "1" same

…calling 🟧 BASE ⬆︎ SL 01 results in:

1 0 1 0 1 1 1 1 0
C: box "1" width 0.15 height 0.2

move previous.width

B7: box "0" width previous.width height previous.height
B6: box "1" same
B5: box "0" same
B4: box "1" same

move previous.width / 2

B3: box "1" same
B2: box "1" same
B1: box "1" same
B0: box "0" same

arc from B1.s to B0.s
arc from B2.s to B1.s
arc from B3.s to B2.s
arc from B4.s to B3.s
arc from B5.s to B4.s
arc from B6.s to B5.s
arc from B7.s to B6.s

arc ← from C.s to B7.s

…but calling 🟦 BITS ⬆︎ SL 02 instead results in:

0 1 0 1 1 1 1 0 0
C: box "0" width 0.15 height 0.2

move previous.width

B7: box "1" width previous.width height previous.height
B6: box "0" same
B5: box "1" same
B4: box "1" same

move previous.width / 2

B3: box "1" same
B2: box "1" same
B1: box "0" same
B0: box "0" same

arc from B1.s to B0.s
arc from B2.s to B1.s
arc from B3.s to B2.s
arc from B4.s to B3.s
arc from B5.s to B4.s
arc from B6.s to B5.s
arc from B7.s to B6.s

arc ← from C.s to B7.s

Rotating

This works much the same except that shifted bits are either sent directly to the other end of the word or shifted through the carry flag, depending on whether there is a C in the function name. (Plain shifting uses the carry flag unconditionally.) Thus the term rotation: it is as if the bits were written on a strip of paper with the ends taped together so that all these functions were doing was choosing a new high bit to start reading the number from.

Starting from the same initial condition as in our shifting examples above, calling RR 04 results in a nibble swap:

1 1 1 1 1 0 1 0
B7: box "1" width 0.15 height 0.2
B6: box "1" same
B5: box "1" same
B4: box "1" same

move previous.width / 2

B3: box "1" same
B2: box "0" same
B1: box "1" same
B0: box "0" same

N1: arc thin color lightgray \
  from B4.n to B7.n \
  behind B7
N2: arc thin color lightgray \
  from B3.s to B0.s \
  behind B0

arc ← from B1.nw to N1.n
arc ← from B6.se to N2.s

dot at N1.n
dot at N2.s

Single-Bit Shifting Functions

The HP-16C wastes a considerable amount of its precious front-panel space giving two overlapping versions of many of its bit-shifting functions: one to shift or rotate the displayed word by a single bit per keypress, plus another which takes an argument for the number of places to shift. One wonders what additional features the HP-16C might have provided had its designers chosen to offer the second type only, being the more general.

The R47 takes the opposite tack. Where it provides a bit shifting or rotating function with the same name as on the HP-16C, it is the version taking an argument. In most cases, the R47’s 🟦 BITS menu provides an alternative with a 1 suffix to shift a single place per softmenu button press; the equivalent on the R47 for the 16C’s SR function is SR1, and RL on the R47 corresponds to RLn on the 16C.

There are discrepancies both directions. The 16C lacks what might be called SLn/SRn equivalents to the R47’s multi-bit shifting operations SL/SR. On the R47 side of the ledger, it lacks RLC1/RRC1 to parallel RLC/RRC on the 16C for want of space in the menu where they’d best fit. Fortunately, these single-bit versions are trivial and may be crafted locally at need in terms of the more general RLC/RRC functions provided.

Arithmetic Shift Right

Plain shifting works out the same as multiplying by 2ⁿ when the direction is to the left, where n is the number of bit places the word is shifted, but does that mean shifting to the right is the same as division by 2ⁿ?

Alas, no, not when the number is negative.

Let us start with the same 11111010 value we got from our RR 04 above, but now call the S08 preset to treat it as a signed two’s complement value. Nothing happens to the binary representation in the X line, but take note of the decimal and hex versions above, overlaying the customary Z and T stack positions. (Details) Instead of interpreting this value as 25010 it shows it as -610. Hmm!

Our question then is, what happens if we shift that right by one bit? We get -3, right?

Nope! 12510, which you will note is half the unsigned representation, 25010. Why?

What happened is that the top bit is set for a negative number in two’s complement representation, and our rightward shift brought in a zero here to fill the gap created by that shift, causing it to be considered a positive number. Unless we are purposefully probing into this type of behavior to better understand how our computers handle this condition, we are unlikely to be pleased with this outcome.

Enter the arithmetic shift right function, which takes care to preserve the sign in accord with the currently-selected signedness setting.

Use the 🟧  function to undo our error in calling SR 01 and call instead ASR 01. What happens to the decimal representation above? It now shows what we expected earlier, -310. Huzzah!

Counting the Number of Bits in a Word

The HP-16C’s 🟦 #B function counts the number of bits that are set within X when expressed in binary. The R47 has that, too:

🟧 BASE HEX
97 ENTER
🟧 BASE BIN
🟦 BITS #B

The third line allows us to visually inspect the input value as a check on the final result: 1012=5, the correct answer.

This result is called the Hamming weight of our input, or in jargon, the “popcount.”

It has many practical uses. In addition to those listed at that link, I can add:

Left-Justification Within a Word

The R47 does provide the HP-16C’s 🟦 LJ function, which does something rather curious:

🟧 BASE HEX ⬆︎ 🟦 U08 
1 ENTER
🟦 BITS ⬆︎ LJ

This sequence causes our R47 to report that it had to shift our given X value by 7 places to get its most-significant bit to the top of that 8-bit unsigned word. The shifted result is up in Y:

`Y = 1×2^7=80_16`

Increasing the word size to allow shifting the X value left by one more bit tells us the number of values our prior word size could represent, 25610.

Another practical use is floating-point scale normalization of the mantissa. The bit shift count LJ yields then goes into adjusting the exponent.

Bitwise Functions

Another class of features often left off lesser scientific calculators are the bitwise operations, and when they are provided, it is generally only the basic set: AND, OR, NOT, and XOR. Count the HP-16C among this feature-limited set, then rejoice that R47 adds the negated forms NAND, NOR, and XNOR.8

Zipping and Unzipping

I promise, the following section is safe for work, rated 🄶 for giggle-inducing fun.

…among people of a certain mindset, at any rate. 🤓

The setup is simple enough:

2 ENTER 32. yˣ 1 -
🟦 # B
0 ENTER
🟦 BITS 🟧

The moment you press F5 to select the ZIP operation, you get this:

ZIP in action

See? Fu-un!9 AAAAAAAAAAAAA! LOLOLOLOLOLOLOLOL!

😃

Bit Masking

Even among scientific calculators with basic bitwise functions, it is rare to see equivalents to the HP-16C’s bit mask construction features, but the R47 does have these. Let’s explore them in terms of the garden variety IPv4 address 172.22.95.232. In R47-speak; that is:

🟧 BASE DEC ⬆︎ 🟦 U32
🟦 BITS ⬆︎
172 🟧 SL 24
22  🟧 SL 16
95  🟧 SL 08
232
⬆︎ OR OR OR
🟧 BASE HEX

We should now see AC165FE8, the hex representation of the same value.

Let us now say we are trying to isolate the host portion of the IP using an oddball CIDR netmask like /25.

R47 to the rescue with its MASKL function:

🟦 BITS MASKL 25 NOT AND

…or, if we are willing to do a bit of grade-school arithmetic off-calculator — 32-25=7 — we can express it more straightforwardly as:

🟦 BITS MASKR 07 AND

Either way, it tells us the host part is 6816.

Base Conversions

Let’s wind down with something easy, something almost any modern scientific calculator can do: integer base conversions.

🥱

But no, wake up, you! In prototypical fashion, the R47 goes far above and beyond its competition in this regard.

Continuing on with our 6816 result above, the natural way to get it in decimal form is 🟧 BASE DEC, yielding 104.

Okay, but why do we care to know this?

All working software people soon memorize the powers of two, up to a point; I don’t begin reaching for a calculator ’til past 218. I offer this humble-brag because it is a trivial observation to me and my peers that 27=128, and the sub-specialty practicing network engineering will additionally understand that one must subtract 1 to account for the IPv4 directed broadcast address in that subnet. Combining these results then tells us that we have 127-104=23 IP host addresses left in that subnet, presuming we also happen to know that addresses were assigned in ascending order without gaps.

#KEYa-f Mode

But is there an easier way? Of course!

When switching into the BASE menu is inconvenient, we might instead make use of the R47’s nifty 🟦 # feature. Selecting this while in numeric input mode — NIM — allows an on-the-fly base conversion. For instance, while in BIN mode, a hex number can be entered quickly as AC#16 or even more briefly as AC#H. Either way, the calculator then shifts into hex mode as a helpful side effect so that further #H annotations are unnecessary as long as one is continuing in hex.

But even better, the very fact that you led this number off with a digit A-F while in binary mode signals the calculator to presume hex input without the need for a # suffix. This takes effect from any starting base, irrespective of whether it is the first digit in NIM or a subsequent one.

(We might wish much the same to occur with 2-9 switching from binary to decimal, but then why not hex for symmetry with the above behavior instead? Or, if your next digit happened to be 2-7, it wouldn’t be impossible that you intended the R47 to infer a switch to octal. Whereas pressing A-F in NIM while #KEYa-f mode is engaged makes one’s intent plain, the other possibilities are ambiguous; making the same leap with 2-9 would result in too many unpleasant surprises.)

This automatic base-switching behavior occurs only while the #KEYa-f annunciator is showing. Engage this implicit mode either by switching into the BASE menu or by pressing 🟦 #. It disengages automatically on entering anything other than a short integer, whether that’s giving a radix mark to produce a real number or something more explicit like calling the 🟧 BASE LINT function to cast X to a long integer.

This mode is also what affects whether the R47 shows the decimal and hex representations of X overlaid where Z and T normally reside. This in turn is why these overlays persist after you EXIT the BASE menu: that is insufficient to automatically disengage #KEYa-f mode.

Implicit base switching is cute, but we often wish to be certain of which base we are switching to. We glossed the #16 annotation and its #H alias above, but the full set of aliases is:

Key Meaning
B binary, #2
D decimal, #10
H hexadecimal, #16
O octal, #8

The advantage of the single-letter aliases may not be apparent. The input field for entering the base numerically takes two digits, so in actuality binary mode is set either by # 0 2 or by # 2 ENTER, three keystrokes either way. The alias saves one. Perhaps of more significance as you gain facility with the calculator, this feature reduces cognitive overhead by making the command to switch into all four major modes the same length. You never have to pause to ask, “Do I need to press ENTER on this one?”

Beware that giving a number the #B suffix is not at all the same thing as calling the #B function.

Any other base requires typing it out as a number from 2 to 16.10 One may use #12 while working on a thesis to convince the world to switch to duodecimal numbering. (Good luck with that!)

With a closed value in X, pressing 🟦 # and hitting ENTER — without giving a new base, mind — converts X to a short integer under the currently set rules. This might be useful when a calculation gave you a real in X but you wanted it expressed in the same base you were using for short integers before.

You might have noticed that immediately on pressing #, a modest one-line menu came up. Selecting one of these items converts the number in X to a base specified in the referenced register, chosen from that menu. For instance, with the R47 in 🟧 BASE LINT mode:

8 ENTER 1234 ENTER
🟦 # →Y

That gives 123410 = 23228 and puts the calculator into octal mode.

Programming

The HP-16C programming model was little different from that of the HP-11C, and what differences did exist are swamped in the R47 by its own programming model differences, being closer to the HP-42S, but not identical.

Once we set these aside, I am aware of only one remaining significant difference in programming the R47 relative to the HP-16C, within their shared domain of short integer manipulation, and it has to do with the 🟧 INTS menu. Why do the A-F items exist, and more curiously, why were they given pride of place in the first row on this one-page menu? That suggests they must be important somehow, but how can that be when there is an equal set of A-F hard buttons a few rows down?

It’s simple: these overloads are inaccessible in program entry mode. If it were otherwise, you could not give instructions like purely on the chance that you might mean to input a numeric literal A digit in base 11 thru 16. Something had to give, so when inputting higher-base constants in a program, you must use these soft menu keys.

The “Missing” Features

We covered RLC1/RRC1 above, but if we run down a list of operations showing on the front panel of an HP-16C, there are a few more that do not have exact equivalents on the R47.

Windowed Numbers

The HP-16C shares the same basic 10-digit LCD design as the rest of the Voyager line; details differ among the models, but not enough that HP could have ordered up a mask variant that allowed them to cram a complete 64-bit number onto the screen. Given their questionable choice to burn two of those digits on the base indicator, the 16C can barely fit the largest 32-bit unsigned integer on screen, and then only in hex mode.

Better would’ve been to move them down into the annunciator line, allowing full 32-bit display in decimal as well, plus 40-bit in hex and 30-bit in octal. That doesn’t get us everything we want, but it would’ve helped at least.

What HP did instead was add the 🟦-shifted operations on the STO/RCL keys to allow scrolling numbers too big to fit on the screen, using it as a “window” into the larger number. They then perpetrated a truly bletcherous hack: they hijacked the . segments on the LCD to indicate which direction(s) the displayed number was incomplete. Arrows matching the ones printed on the keys in the annunciator line would’ve worked far better.

I’m not going to try to explain or defend this feature further, because it sucks. Flat sucks.

And the R47 doesn’t need it. The screen is large enough to show octal, decimal, and hex numbers in their full precision up to 64:u in the standard display font, and for binary it switches to one of two different small fonts to cram everything into the space available without scrolling or wrapping. (One of the options it can resort to is shown above.)

This very factor is one of the things that had me off in PC-based calculator land for so long. It undermines the claimed simplicity of a dedicated calculator if you cannot see and understand your results at a glance.

FLOAT Mode

FLOAT is the 🟧-shifted function of the HP-16C’s RCL key. Nowhere will you find FLOAT printed on the R47 keyboard, nor upon its faceplate, nor listed in its 🟧 CATalog.

A seasoned software developer reading this may become miffed on learning of this lack, thinking they’re missing out on a built-in method for examining IEEE 754 floating-point values in binary or hex form. Such a feature could be useful in debugging low-level code where your tooling cannot translate the raw bits back into FP representation for you, or the reverse, as might occur when looking for a given FP value in a hex dump.

For better or worse, this feature of the HP-16C actually corresponds to FIX mode on its Voyager family-mates, taking the same 0-9 length argument. The 16C could also be put into a hard-coded SCI 6 mode with the 🟧 FLOAT . key sequence. It uses the same 56-bit decimal floating-point representation, offering a 10-digit mantissa with a 2-digit exponent, but when you switched into or out of the 16C’s default integer mode, it gave a garbage result because it did not even try to convert the data type, as the R47 will, with great facility.

FLOAT mode doubtless has its uses, but objectively, these weaknesses and more meant engaging it turned the 16C into an even more crippled scientific calculator than the brutally feature-reduced and ill-fated HP-10C. While it would be unfair to class this as a “toy” feature, it certainly has limited utility to a practicing software developer. It might save one the need to reach for a proper scientific calculator when needing real-number results, but then again, maybe not! You might want, let us say, a log₂(n) function for calculating the cost of searching a binary tree; but alas, no logarithms on a 16C, sorry!

Even the vaunted HP-15C lacks that one,11 but the R47 offers it as 🟦 EXP LB, so-called because it is the “binary” logarithm. You get this and tremendously more in the R47 because it contains one of the most powerful handheld calculating engines available. There is no artificial product segmentation as when HP divided the world into 15C and 16C users, doubtless with secret hopes that those spanning this arbitrary border buy both.

The R47 looks at this FLOAT gap and says, “What gap?”

An Amusing Appendix

If you are one of those who really do want those IEEE binary floating-point functions in your R47, SwissMicros forum member @danielCL has graciously provided programs to produce both double and single-precision floats from an R47 real number.

Appendix D in the HP-16C user manual gives a matched pair of single-precision programs for bidirectional conversion, but alas, they cannot be ported to the R47 without significant modification. I am not speaking of trivial matters like the differing capabilities of LBL between these two machines. No, the key sticking point is that these programs rely on that same hard-casting behavior derided above: program B starts in FLOAT mode with the input value in X and switches immediately to HEX mode to produce the bitwise representation of the value in the Voyager 56-bit decimal FP format. Program A inverts this.

The primary value I got out of reading this historical appendix before I gave up on my porting plan is to note that it refers to IEEE 754 as a “proposed” standard since the HP-16C predates the first formal IEEE publication by three years. 🤣

(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


  1. ^ 2-page menus have the valuable property that you can press ⬆︎ or ⬇︎ interchangeably to get to the other page. Menus with 3 or more pages burden the user with an incentive to memorize which direction functions not on the first page may be found.
  2. ^ One with base conversion features, that is, thereby excluding the HP-21S statistics-focused model. The “scientific” qualifier already ruled out the business-focused Pioneers. Later tests showed that the HP 35s does the same thing, and so presumably will the 33s.
  3. ^ Yes, my child, “bytes” were not always 8 bits in size.
  4. ^ Note that this is never characterized as 48 KiB of memory because accessing data as 8-bit bytes with the PDP-8’s famously sparse instruction set was annoying enough that cycle-optimizers were more likely to resort to 6-bit “bytes” to save space on printable strings, resulting in an assortment of incompatible 7-bit ASCII subsets, primarily leaving out lowercase and an idiosyncratic selection of symbols and control characters. This was sensible at the time because ASCII was hot new tech when the PDP-8 came out. They hadn’t even fully settled on the acronym yet; you can find old docs referring to USA-SCII, for instance, from before the time that the United States of America Standard Code for Information Interchange got sanded down to “American…”
  5. ^ STM32U575 = ARM Cortex-M33 family = ARMv8-M instruction set.
  6. ^ This was spelled DBL/ in the R47 prior to 2025.12.20 as a legacy of the WP43 fork, which uses / to indicate division.
  7. ^ If you are now wondering why the R47 gives both RMD and MOD, they differ for quibbly reasons when it comes to negative numbers.
  8. ^ That’s four primary functions but only three negated versions. What gives? The fourth would be NOT NOT, which is a no-op on a calculator. It’s useful in languages like C, however, where the ! operator takes any truthy value and returns false, which then allows construction of what I call the “truthiness operator.” The value of !!foo is always 0 or 1 in these languages rather than zero or nonzero, a fact that can become useful in bit manipulation code.
  9. ^ If you disagree, I have to wonder why you have read this far, because clearly we do not agree on what constitutes G-rated fun.
  10. ^ Base 0 is mathematical nonsense, but now that I think about it, I find myself wanting a base 1 mode that expresses the result in tally marks. 🤣
  11. ^ Please, hold your replies. Yes, I do already know that `lb(X) = ln(X)/ln(2)`