Motivation
Take the classic HP-11C: all user inputs are stored in BCD registers, irrespective of any semantic meaning attached to those numbers. That was standard industry practice in 1981 when it came out, but a year later HP broke that mold with the 15C, which offered complex number and matrix support. These were firsts for HP, but as revolutionary as they were at the time, the R47 takes strong data typing to a whole other level.
Because this has practical import on how one should best use the calculator, I will go into a certain amount of detail about this now without exceeding my user-focused mission parameters. Details not visible from the user interface will not intrude on our attention here; that’s what the source code is for.
ℝ: The Real Numbers
Aren’t all numbers real, at least to the extent that the cerebral study of pure mathematics allows? Anyone old enough to be reading this has seen fictitious numbers in marketing and the media, but this is not what is meant by the mathematical distinction “real.” Nor are they speaking of the oft-seen divorce between paper results and practical reality. This classification comes from number theory, which defines real numbers as:
…[those] that can be used to measure a continuous one-dimensional quantity such as a length, duration, or temperature.
— Wikipedia on Real numbers, first sentence paraphrased
In other words, it is the typical sort of thing we put into calculators and get out as results.
Technically, the R47 implementation of this is not “continuous” as the definition requires, but that is because the chip makers have not yet seen fit to grace us with infinite memory or infinite processing speed. What we get instead are floating-point numbers, an approximation to ideal real numbers. It is possible to craft tests demonstrating the loss factor, but whereas typical computer programs use 32-bit or 64-bit binary FP values for speed, the R47 stores values in a 128-bit decimal FP format to make the loss meaningless in practice. 64-bit FP (a.k.a. “double precision“ relative to 32-bit) is capable of delivering 15 or 16 digits of precision depending on the exact way the numbers are represented, whereas the 128-bit representation in the R47 can reliably hold 34 digits.
In the R47, we call these “reals” to avoid saying “real number” plus the preceding as a quibbly qualifier.1
decNumber vs IEEE 754-2008
There are actually two primary2 real-number formats within the R47:
- IEEE 754-2008 standard densely packed decimal format, used for storage in registers, state files, etc.
struct decNumber, the eponymous data format used within the IBM decNumber library at the calculator’s core
Comments in the code sometimes distinguish these as the 34-digit and 39-digit forms, but that is a mere internal implementation detail having effect within the calculator’s RAM only. All I/O paths begin or end with the 34-digit packed form.
Why 34 Digits?
If all we wanted was to represent integers in binary format, we could first observe that `2^128 ~= 10^38`
Knocking the edge conditions off allows us to drop that “approximate” qualifier and claim 37-digit accuracy.
The reason we lose these 3 orders of magnitude of range is that the densely-packed decimal floating point format trades away some of the space efficiency of a pure binary representation in favor of improved accuracy.
Rounding Behavior
When the R47 runs out of precision to hold a real-number result, it does not simply truncate it; it rounds it.
The everyday case is display rounding, where the R47 is taking a value from the stack and working out how to put it onto the calculator’s LCD. For this, it always rounds away from zero. You can demonstrate this to yourself thus:
🟧 DISP ALL 19
.111111111111111111111
.555555555555555555555
The exact number of digits in these entries is not the important detail; you merely need to enter enough to make it start showing it in the small font, indicating that there are more than it can display, forcing the rounding behavior given our chosen ALL 19 display mode. The final digit for the first entry will remain an un-rounded “1” but for the second it will be rounded away from zero to “6”.
Why write that as “away from zero” and not simply “up?” Is your humble author prone to excessively convoluted modes of self-expression? Betimes, yes, but not in this specific case. Re-enter that .5̅ value but hit CHS before ENTER to see why. If it was rounding “up,” that sign change would make the last displayed digit a 4, not 6.
SIG mode and the SDIGS setting give you two ways to get rounding shy of the display limit, but if you wish it to occur on demand for a single value, you may prefer to use the RSD or RDP functions: Round to Significant Digits or Round to Decimal Place. Both take an argument like SDIGS, but they apply only to the current value in X, replacing it with the rounded-off value.
In addition to affecting subsequent RSD/RDP calls, RMODE is also documented as “…used when converting from the extended precision internal format to packed reals,” glossed above. By spelunking into the C code, I have found a few more cases where RMODE is consulted:
- Rounding decimal time values as part of the implementation of the
x≈?test3 - Adding an offset to a date, which starts by rounding the real offset to an integer
In every other instance, the code uses a hard-coded situation-dependent rounding mode. For instance, calling 🟦 REAL IP to return the integer part of a real always rounds down.
RMODE may be any of:4
| # | Meaning | Sym |
|---|---|---|
| 0 | half rounds to even | ½E |
| 1 | half rounds up | ½↑ |
| 2 | half rounds down | ½↓ |
| 3 | round away from 0 | ←0→ |
| 4 | round towards 0 | →0← |
| 5 | round towards ➕♾️ (ceiling) | ⎡x⎤ |
| 6 | round towards ➖♾️ (floor) | ⎣x⎦ |
RMODE does not affect display rounding, being effectively hard-coded to mode 3.
The most logical access path to this setting5 is 🟧 PREF ↑ F5 where you can see the current mode’s value in order to look it up in the “#“ column above, plus also change it using the same numeric mode mapping. More useful if you just wanted to see the current setting is 🟧 FLAG STATUS where one of the “Sym” column annunciators follows the RM= readout.
Integer-to-Real Conversion
In normal use, one rarely has to go out of their way to get a real on the stack. Simply input a value that includes a decimal radix, or do a calculation that produces a fractional part. The most common case where it matters whether you have a real on the stack or an integer is in the R47’s handling of number formats: those settings typically apply to reals only. There are several ways to force the matter. In order of decreasing simplicity:
While in numeric input mode, press the
.key immediately before pressing anything that causes a stack lift. Saying123ENTERgets you a long integer, whereas123.ENTERgets you a real.With a closed number in X, press
.+to add a real-typed zero to it, converting X to a real where possible.6With a closed number in X, press
🟦.dBeware that this easily missed function above the
yˣkey is overloaded based on context and input value. If you call it from numeric input mode — NIM — its meaning changes:- when given a radix, it tries to interpret the value as a legacy HP decimal date (
yyyy.mmdd) and complains about implausible results7 - when given an integer, it acts like you hit
ENTER
It may be helpful to think of the “d” in this function’s name as referring to both “decimal” and “date” to avoid surprises. This potential confusion explains why this option ranks third despite taking but two keypresses: the prior option is less ambiguous.
- when given a radix, it tries to interpret the value as a legacy HP decimal date (
Press
🟦CPXReThat function returns the real portion of a complex number8 but when given an integer, it converts it to a real. I include this option for completeness, not because I think digging this deep into the menus to accomplish this simple end is somehow better-because-cute.
Binary vs Decimal Floating-Point
HP calculators have always used an internal number format called binary-coded decimal, or BCD. The R47 uses a more sophisticated format for real-number calculations called decimal floating point, giving the same accuracy benefits by grace of the exceptional IBM decNumber library, which it incorporates.
The primary alternative to decimal FP or old-school BCD is binary floating-point, which modern computers prefer since it is space-efficient and fast when implemented in hardware. When extreme accuracy is not critical, this is the right tradeoff, but otherwise, you can run into problems.
I must stress that this applies only to reals on the R47, which is why I cover it here. There is a separate setting (🟧 PREF→CFLG→BCD) which appears — on reading the code — to affect the display of short integers, plus also the T register and not the others, for some strange reason. I recommend leaving this flag in its default-off setting unless you know what you’re doing. The R47’s real-number decimal FP already is “BCD” for practical purposes.
Integers
The R47 has a few different types of integers, and it can be important to understand the distinctions.
ℤ: Long Integers
Mathematicians will tell you that ℤ refers to the set of all integers, but we use it here even though that ideal is beyond the R47’s finite limits: 1000 digits or less, plus a sign.
That will usually do nicely.
When you input a number without a radix mark, you get a long integer by default. It is important to realize this because several top-level behaviors of the R47 depend on having a real instead, the most prominent of which are the number display modes.
There are opposing cases where you have a real but actually do want a long integer, and for that the calculator offers 🟧 INTS 🟧 LINT.9 A shorter option is 🟦 →I but beware that pressing it with a long integer already in X will convert it to a short integer, which may be lossy.10 A third press cycles back to long.
Current behavior as of this writing is to add a leading ℤ: indicator when the calculator’s display engine runs out of space to fully display a large result, in which case it also shifts into exponential format. It does both because exponential notation is more commonly associated with real numbers, and it is trying to avoid misleading the user into an incorrect conclusion. With a default setup, you can see both sides of the border with 21! and 22!
You may wish to make this unconditional by setting the 🟧 PREF CFLG dℤ.0 system flag. It is much harder to miss a big ol’ blackboard bold ℤ: prefix than to notice the lack of a decimal radix mark.
Short Integers
C programmers beware: what the R47 calls a “long integer” is not a long int, which is instead one possible variety of “short” integer in R47-speak, which might correspond to your favorite programming platform’s short int… Or it might not!
Confused yet?
R47 short integers are far more flexible than any single C compiler, much less a given target CPU’s hardware ALU. The R47 tries to cover the union set size of integer handling in all C compilers and all CPUs. Down this path lies the topic of the R47’s built-in HP-16C superset, but let us not get distracted.
Keeping our focus on data types, what this means is that while the values R47 calls short integers are fixed-size words, you have the option to change its word size to anything from 1 to 64 bits, giving a maximum value of 264 ≈ 1.8456×1019 in unsigned mode, or approximately half that in the various signed modes.
While you can force X to a short integer via 🟧 INTS 🟧 SINT, the more common path is to set the word size under the 🟧 BASE menu to match the behavior of a given CPU.
There’s one more secret feature here: pressing 🟦 # on a closed X but then hitting F gives the fractional part of X as a real, and pressing I gives the integer part as a long, thus in base-10 irrespective of the short integer settings.
ℚ: Fractions?
You might guess that the R47’s fraction mode is implemented as a data type binding two integers together,11 allowing it to maintain a value like ⅔ as a rational number, but that is not currently the case, nor is that likely to change. It is purely a numeric display mode atop the underlying value, which is most likely a real.
ℂ: Complex Numbers
The R47 has first-class support for complex numbers. Contrast the 15C, Hewlett-Packard’s first attempt at supporting this, where they achieved this end in the simplest way possible: by adding a parallel set of stack registers for the imaginary part. Both machines will produce the correct result on asking it for the square root of -1 — 𝒾 — but the R47 goes further.
We see the superficial level by observing that the HP-15C implies that the answer is 0 until you call on its 🟨 Re↔︎Im function to swap the imaginary part into the displayed (real) part of X and hide the real part away in the X register of the imaginary stack. This hack was acceptable in 1982 for a battery-powered calculator, but it is the R47 that gives us what we actually wanted, displaying 1.𝒾 in its default setup, with the radix mark indicating that 𝒾 is being multiplied by a real 1 and not an integer 1.
Down at the programming level, the R47 offers the test function ℂ? which is not merely looking at a pair of registers and asking whether one or the other is nonzero. It will return true for 0.0+0.0𝒾 as well. Why? Everybody sing: data typing!
The R47 allows direct complex number input without the gymnastics required by primitive implementations. Pressing 2 🟧 𝒾 4 will put 2.+4.𝒾 on the stack in the default number format mode.
Another option is to put the real part in Y and the imaginary part in X, then hit 🟧 COMPLEX, above the ENTER key.
Still another way is to exploit the √-1 test shown above, allowing us to reproduce the above example thus:
1 CHS √𝑥
4 ×
2 +
𝔻: Dates
The R47 supports two different date formats: the old HP real format (yyyy.mmdd) and the new properly data-typed form referred to in menus with the double-struck 𝔻. It can convert between them freely, but the latter is more flexible and powerful. Case in point:
2025.1231 ENTER
.0001 +
I have taken the end of the year as I write this and attempted to add 1 day, but instead of rolling over to 2026-01-01, it tries to convince me that the following day will be the 32nd of December. If I say instead:
2025.1231 ENTER
🟦 CLK 🟦 x→𝔻
.0001 +
…I now get the expected result, plus a bonus: the R47 tells me it will be a Thursday.
Pedants beware: Before you write in, I am already aware that there are correct ways of working with old HP decimal date arithmetic on the R47. My point is not to paint these features as broken, merely to demonstrate that the R47’s date format avoids the need to be as careful specifically because it is a data type and not merely a specially-formatted real number.
𝕋: Times and Intervals
The situation here is much like with date values: there is the old HP HH.mmss real number format and R47 𝕋ime format, which is less likely to get you into trouble by being properly data-typed.
One of the things that falls out of this distinction is that the R47 does not conflate the concepts of time and sexagesimal degrees, as old HP machines do. While it is true that both systems are based on sixty seconds to the minute, with sixty of those per major unit, it breaks down at 360 degrees in a circle versus 12 hours around the “circle” of an analog clock, or 24-ish hours in the apparent circuit of the sun’s travel over the Earth. Thus the error when you try something like this:
12.3456 ENTER ENTER
🟦 CLK 🟦 H.MS→𝕋
x≶y
🟦 TRG 🟧 ⇒D.MS
+
It rightly complains, “Invalid input data type for this operation.” If it allowed the attempt, it could only produce nonsense.
This data type is used for both intervals such as 00:34:56 — interpretable as a bit over half an hour — and as absolute times such as 12:00:00 = high noon. These are first-class data values, allowing you to add them to get 12:34:56.
There is no associated time zone, and it does not try to handle any of the other complexities like UTC vs UT1.
Setting the Time
By way of example, let us now set the calculator’s RTC…the hard way! We’ll say it’s a bit after five-thirty post meridiem, but because the R47 does not understand “p.m.” in input values, only as an output format, we will anticipate a near-future time…
17 ENTER 30 ENTER 15
🟦 CLK 🟦 zyx→𝕋
⬆︎ 🟧
…and now we hover our finger over the second soft-menu key with an eye on our reference clock…
…5:30:13 PM…
…14…
…15! Pressing F2 calls SETTIM, copying the 𝕋ime value in X into the calculator’s RTC.
There is a cost to this method: it temporarily eats 3 stack registers. This is tolerable in the default SSIZE8 mode, but if you have switched your R47 into SSIZE4 mode for historical HP compatibility, you now have three copies of T above the freshly minted time value in X.
We can avoid that by making temporary use of the legacy HP decimal time format, HH.MMSS:
17.3015 ENTER
🟦 CLK 🟦 H.MS→𝕋
⬆︎ 🟧 SETTIM
We can verify that this old-school HP value has been upgraded to a proper R47 time-typed value via the key sequence INFO ⬇︎ F1. That calls the TYPE? function, which reports 3 with “Time” off to the left. If you dig into the R47 reference material, you can find a table of data types, where 3 is more formally described as a “Time or time interval.”
This is the meaning of that mathematical double-struck “𝕋” in the menus.
Time Arithmetic
Given the X value above, what happens if you add 1?
1 +
18:30:15
Aha! It has interpreted that bare integer as “one hour” and handled the addition accordingly.
One may then guess that to add one second, one would add 0.0001 per the old HP rules, right? Nope, sorry, because the R47 must be consistent and continue to interpret that input as hours. 0.0001 therefore means “one ten-thousandth of an hour,” or 0.36 seconds. We must convert it from classic HP notation first, same as above, but the R47 offers a shortcut via the faceplate-level 🟦 .ms function, above the 1/𝑥 key; no need to dig into the 🟦 CLK menu. Evidently, the R47 designers considered this conversion valuable enough to give it a hard-labeled keyboard function slot.
Adding this type-converted value yields the expected new time value.
Beware that the meaning of .ms changes based on context. To get the intended behavior here, you have to call it from NIM. (That is, with the number entered but without having hit ENTER.) If instead you start with a closed value in X, the first call to .ms assumes fractional hours, not HP-style BCD time format, thus gives you 0.36 seconds again.
Displaying the Time
While the R47 does not show the current time in the upper line of the display to save battery life, you can retrieve it and observe that it has advanced from our setting above via 🟦 CLK 🟦 Time→𝕋.
This value can be manipulated in the ways suggested above. For instance, on noticing that the RTC has drifted significantly, you could add a correction value, then call SETTIM to apply the adjustment.
Angles
The R47 supports several angle data types, distinct from the angle display mode (ADM) covered elsewhere.
Sexagesimal Degrees
Known more verbosely as the degrees-minutes-seconds mode or as D.MS in on-calculator abbreviations, this works much like time values while being strictly distinct from them on the R47. Contrast old HP machines, which conflate the concepts due to a lack of proper data typing.
The R47 is hardly unique in offering this mode,12 but it does take it to a level few others do. It is because it treats these sexagesimal degree values as distinct from the more usual decimal degrees that you can do things like this:
🟦 TRG D.MS
1 DRG
ENTER
0.5 ×
+
The first line tells the calculator to produce sexagesimal results by default.13 Setting it saves us from making multiple calls to the one-shot 🟧 ⇒D.MS function above the unshifted D.MS ADM-setting button to force the conversion at each step.
The second line exploits a somewhat hidden feature of DRG: when X contains something other than an angle, the first press converts it to the selected ADM. If that ADM is outside the common DEG-RAD-GRAD sequence, it takes four presses to get through the first cycle, not three. Otherwise, the first press jumps you into the middle of the cycle per your ADM selection.
Thus, the second line produces 1°00' 00.0” in X, and pressing DRG a second time would convert this to decimal degrees. To get the value back into sexagesimal form, we would have to either reenter “1” with the ADM still set to D.MS per that first line in the sequence above, or call the one-shot 🟧 ⇒D.MS function on it to force the conversion. Setting the ADM saves keystrokes in the common case where you want results to be in a particular format regardless of the input data types. The R47 converts as necessary.
We don't need to hit DRG after the ENTER on the third line above because stack item duplication also copies the D.MS data type tag. Halving that second copy produces a D.MS typed value for the same reason: multiplying an angle by a real number produces an angle, and because we have not changed the ADM, the resulting X value is shown in D.MS format.
The closest I can get to matching the above sequence’s result of 1°30' 0.00" on my HP 35s is:
1 ENTER ENTER
0.5 ×
+
→HMS
Prior to the last step, it will be showing 1.5000e0 in its default FIX 4 mode, which is only correct if you wanted decimal degrees and not d.mmss format sexagesimal. It is not until the final step that we get the desired output format, and then only so long as we are willing to tolerate 1.3000e0 as an acceptable way of reporting “one degree and thirty minutes of angle.”
Yet let us be charitable and hand-wave this display detail away. We will also choose to ignore the fact that the 35s lacks a proper time type, resulting in a conflation between its HH.MMSS and DD.MMSS notations, both being mere display conventions for regular numbers. Unlike the R47, the 35s will blithely allow you to add degrees to hours, but where we really see the model break down is attempting to add 31 minutes to the result by saying .31 ENTER +. It now reports 1 degree, 61 minutes, demonstrating that the HP 35s does not truly understand sexagesimal degrees despite being a fairly late-model device.
Compare the R47’s smooth handling of this same test:
1 DRG
ENTER 0.5 ×
0.31 DRG
+ +
It correctly reports 2° 1' 0.00" because the machine is still in D.MS mode from above, which is why we need to press the DRG mode button only twice, and we do not need to make any explicit ⇒D.MS calls.
All this having been said, the R47 will also accept HP-style BCD-coded sexagesimal degrees as input, but then immediately apply proper data typing. We can reinput our result above so:
2.01 🟦 .ms 🟦 .ms
This works because the first press tries interpreting the numeric input as 2:01:00 hours, and the second reinterprets it as the angle 2° 1' 0.00". A third press cycles back to hours.
Beware that the same NIM surprise we observed above also occurs here: starting with a closed value in X causes the first call to .ms to assume fractional hours, not HP-style BCD time format, thus gives you two-and-one-hundredth of an hour = 2:00:36! A second press therefore gives you 2° 0' 36.00", which may or may not be what you wanted.
Multiples of π
While the final ADM in the R47 is uncommon in other calculators, it is exceedingly common to find it in secondary school math textbooks. It is simply radians with the π factored out, so that instead of showing the arctangent of 1 to be 0.785 radians, it shows 0.25πr.
You may recognize this in its more common presentation, `π/4` radians.
What would be really cool is if this mode played nice with 🟧 DISP 🟧 FRACT mode and showed the value in type-annotated textbook form, but alas, it does not. What does work is this:
As you can see by the type tag, the Y value in this example was produced with ADM set to MULπ, but X is in radians. The key setting here is that we have IRFRAC enabled — thus FRACT disabled — which gives the R47 the freedom to factor out the π in the same manner as MULπ while in regular radians mode. This gives us a fair approximation to the textbook display above.
Strings
When you enter alpha input mode — AIM — from the normal stack view, the value between the quote marks is a distinct string type. It is not an arithmetic type; adding 5 to ‘Hi’ produces ‘Hi5’ — 🙌 — not an integer based on the underlying numeric data representation of the string.
Matrices
I currently have little to say about the R47’s matrix data type, except that there are two, not one. Under the hood, it treats a matrix of complex numbers as distinct from a matrix of reals. Beyond that, all I can presently offer is this lame cop-out:
🚧 Document Under Construction! 🚧
Vectors
A vector is often expressed as a list of numbers with a length equal to the number of dimensions in the coordinate space.14 This may in turn be thought of as a single-column matrix, which is how the R47 does in fact treat vectors.
There’s one big trick, though: to save screen space, it outputs vectors on a single line in “transposed” format, marked with a superscript “T” to the right. Thus, these two inputs result in nearly the same [0. 0. 0.] display, differing only in that transposition marker:
🟧 MATX
1 ENTER 3 NEW
3 ENTER 1 NEW
The first creates a single-row 3-column matrix, whereas the second creates a single-column 3-element vector.
(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
- ^
Of all the terms we could use here,
REALfits onto the calculator faceplate best. - ^ The secondary formats are the ASCII string representations used for numeric input from the keyboard and for output to the display.
- ^ It’s necessary for proper time value handling because fractional seconds are commonly encountered, whereas fractional dates are little more than a cutesy way of implementing date-and-time values.
- ^
I happened to pull these values from the C47 code, but they are also documented in the reference PDFs. Beware that these tables are a reordered version of the underlying decNumber mode set. One key take-away is that R47 and decNumber do not have different rounding modes, merely different mode orderings. What decNumber calls mode 3 and sets as its default is R47 default
RMODE0. - ^
Those that prefer tricky paths may find this same screen via
🟦FLGS⬇︎⬇︎⬇︎. That’s one more keystroke than the⬆︎⬆︎path, but your finger is already over⬇︎, making it the faster path for those willing to memorize wizard incantations. - ^
It can’t be done in some of the modes accessed via the
BASEmenu, for instance, which force numbers into short integer formats. - ^
Beware that it will interpret
yy.mmddas < 100 A.D. - ^
Another path costing one additional keystroke is
🟦REAL🟦Re - ^ It is not referring to the contents of your clothes dryer’s exhaust trap. 🤣
- ^ It will warn you about an overflow condition and allow an undo if this occurs.
- ^ …or three, for mixed fractions
- ^ Even my lowly Casio fx-260SOLAR can do this properly, if not as prettily. This basic school calculator can do what classic “professional grade” machines from HP cannot, even at multiple times the price. What once was fancy is now table stakes.
- ^
Prior to release 00.109.03.00b0 this had to be chased down via the operations catalog, but it is now a fully-fledged peer to the common degree modes
DEG,RAD, andGRAD. - ^
C++ abuses this notion with its
std::vectortemplate data type. Avector<uint8_t>is numeric if you squint, but it is more commonly used as a fancy byte array, thus has more in common with a string than a mathematical vector. And don’t get me started onvector<bool>! 😱