(Comp.sys.hp48)
Item: 3867 by jamesu@anacad.fr [James Unterburger]
Subj: HP48 floating point ML suggestions
Date: 23 Feb 1994
[Note: The JAZZ library's assembler recognizes Inf (infinity) and NaN
(Not a Number) as valid objects. These were described in the HP-71
literature ten years ago, and were never mentioned again... until this
article. Thanks, Jim! -jkh-]
Here is what I think I know about HP48 (and HP71B) floating
point. If I'm wrong in any detail, please let me know.
The entry point addresses are for the HP48SX-E, but are
supported entry points, so should be the same on any HP48
version.
A "split" floating point number
is held in two registers. I call this a "15-form" number
(throwback to HP71B terminology). It is obtained by calling
SPLITA (#2BC4Ah) with a "12-form" number in A.W. Or if you
have two 12-forms, one in A.W and the other in C.W, you can
call SPLTAC (#2BCA0h), which returns two 15-forms, in A/B and
C/D (the "/" does _not_ mean "division", it is simply notation
showing the location of the 15-form split extended real).
Each of these routines returns in DEC mode. If you need
to know how a 15-form number is stored in the two registers
it occupies, it's like this (X is don't care, M is mantissa
digit, E is exponent digit, S is sign nibble):
12-form: SMMMMMMMMMMMMEEE
15-form: SXXXXXXXXXXEEEEE
XMMMMMMMMMMMMMMM
Notice that you get 15 mantissa digits (hence the term 15-form)
for an extended real. When you first split a 12-form into
a 15-form, the extra three digits will be zeros. The SPLITA
and SPLTAC routines also check for "funny" inputs in that
Inf and NaN (not obtainable on the HP48 from user-level
operations) are handled. For Inf and NaN inputs,
Carry will be set upon return. Otherwise, Carry is clear.
Also, the numbers are "normalized"
meaning that if the first mantissa digit is zero, the mantissa
is shifted left (and exponent adjusted accordingly) until the
first mantissa digit is non-zero.
To add two real numbers in ML, the routine RADDF is the
one that I use. It expects two 15-form extended precision
reals in A/B and C/D and returns the sum in A/B. It uses
the D0 register (and ABCD obviously). It should be called
with the mode set to DEC (SETDEC instruction). To subtract
C/D from A/B, simply issue the C=-C-1 S instruction (in DEC
mode) before calling RADDF. RADDF is at #2B7CAh.
To multiply A/B by C/D, call MULTF (#2B91Eh). It does not
use the D0 register, thankfully.
To divide A/B by C/D, call DIVF (#2B977h). It doesn't use
D0 either. Special cases (like Inf and NaN) are trapped
partially I believe, but can't be sure. A better
(unsupported unfortunately) entry point is ((=DIVF)-6)
which is the same as DIVF except that Inf and NaN are checked
for as inputs as well. (NaN can be considered the "Undefined
Result")
As a matter of fact, RADDF, MULTF, and DIVF all have, 6 nibbles
before them, the old HP71B code which checks for Inf and NaN
as inputs and handles accordingly. Generally, this type
of exceptions causes the [XM] bit of the hardware status
to be set. P==3 for Inf and P==4 for NaN as well. If you
want to know more about these hidden HP71B remnants, read my ML
code for the TRID (tridiagonal matrix system solver) program which
makes full use of them. If you want a copy, just let me know.
jamesu@anacad.fr
James Unterburger