The Museum of HP Calculators

Packing Long Integers for the HP 71B (Assembler)

This program was written by Valentin Albillo and is used here by permission.

This program is supplied without representation or warranty of any kind. The author and The Museum of HP Calculators therefore assume no responsibility and shall have no liability, consequential or otherwise, of any kind arising from the use of this program material or any part thereof.

Overview

Here included is a LEX file I wrote some time ago, when one of my customers just happened to own a 71B for corporative uses, and was in the process of writing a Bill of Materials program for it. But life's never so easy ...

He had a big problem: he needed to have in memory (16K) a large array of costs. Each cost ranged between $0 and $10,000,000 say, whole numbers, no cents. Due to that range he was forced to use REALs, which took 8 bytes each, thus limiting the maximum capacity to less than 2,000 numbers. I suggested him compressing the numbers as alpha characters, but the packing and unpacking routines took too long to run, slowing the program to an unacceptable degree.

It seemed to me that the ideal solution would be to have the routines implemented as assembly language BASIC keywords, and this LEX file was the result.

Description

This assembly language listing, when assembled using the FORTH/Assembler ROM for the 71B, creates a LEX file called PACK3, which adds two new keywords to the BASIC language, namely PAK and UNPAK.

Its main advantage is obviously the greatly expanded integer range, from 0 to 16,777,215 in just 3 bytes, compared to the normal 71B INTEGER range which stores only from -99,999 to 99,999 in 4 bytes.

The savings are 5 bytes per item compared to using REAL precision, so it allows the user to cram more than twice as much data as before in the same or less space.

BASIC Sintax


    Packing:     A$ = PAK$(N) 

                 where N is any numeric expression which returns an integer-valued
                 real in the range 0 to 16,777,215.
 
                 The result will be a 3-character string.

                 Execution time (aprox.):  14.6 milliseconds 
 

    Unpacking:   N=UNPAK(A$)

                 where A$ is any string expression which returns a 3-character
                 string.

                 The result is an integer-valued real in the range 0 to 16,777,215

                 Execution time (aprox.):  11.6 milliseconds

The Program

This listing should be entered into a TEXT file, using the ASCII Text Editor available in the FORTH/Assembler ROM, or any other suitable text editor.

Then, it should be assembled using the Assembler in that ROM, which will produce the PACK3 LEX file in memory. Once PACK3 is in memory, its keywords are available for inmediate use (don't forget to turn off and on the machine, to register the new LEX file with the 71B's operating system).

Alternatively, you may use any other 71B assembler (such as anyone written for execution on a PC) and then read the resulting LEX file from a disk. Consult your assembler's documentation for the required procedures.



       LEX 'PACK3'        name off the lex file: PACK3
       ID #54             LEX id: 54
       MSG 0              no error messages
       POLL 0             no poll handling
EXPR   EQU #0F23C         resumes expression evaluation
FLOAT  EQU #1B322         converts a decimal integer to floating point
HXDCW  EQU #0ECB4         converts a hexadecimal integer to decimal
RJUST  EQU #12AE2         converts a floating point to decimal integer
DCHXW  EQU #0ECDC         converts a decimal integer to hexadecimal
FNRTN1 EQU #0F216         returns the value of the function to the system
POP1N  EQU #0BD1C         extracts a floating point from the stack
POP1S  EQU #0BD38         extracts a string from the stack
       ENTRY DTH          1st keyword: entry in DTH
       CHAR #F            1st keyword: is a function
       ENTRY HTD          2nd keyword: entry in HTD
       CHAR #F            2nd keyword: another function
       KEY 'PAK$'         1st keyword: PAK$(N)
       TOKEN 1            token 1 in this lexfile
       KEY 'UNPAK'        2nd keyword: UNPAK(N$)
       TOKEN 2            token 2 in this lexfile
       ENDTXT             end of tables
       NIBHEX 811         PAK$: string function, 1 numeric parameter
DTH    GOSBVL POP1N       get parameter (floating point) from the stack
       GOSBVL RJUST       convert it to a decimal integer
       C=A    W           copy it to C
       GOSBVL DCHXW       convert it to hexadecimal integer
       P=     5           point to the 6th hex digit
       D1=D1- 6           send digits 1st-6th to the stack
       DAT1=C WP
       C=0    W           preparing the header: 6-nibble string
       P=     0
       LCHEX  60F
       SETDEC
       D1=D1- 16          send header to the stack
       DAT1=C W
       GOVLNG EXPR        return to system
       NIBHEX 411         2nd keyword: numeric function, 1 string param.
HTD    SETHEX
       GOSBVL POP1S       extract string header from the stack
       C=0    W           extract string (6 nibbles) from the stack
       P=     5
       C=DAT1 WP          its 6 nibbles are placed in C
       D1=D1+ 6
       GOSBVL HXDCW       convert those 6 hex digits to decimal
       GOSBVL FLOAT       convert this decimal integer to floating point
       C=A    W
       GOVLNG FNRTN1      return to system
       END

It should be 90 bytes once assembled.

Examples

            PAK$(4276803)  gives:  'ABC'   


            UNPAK('ABC')   gives:   4276803

Notes

This LEX file does not do any kind of error checking, so as to be as short and fast as possible. Therefore you should be extra-careful that:

Further development

This LEX file was the solution to the problem of my customer: he now had two new BASIC keywords that would take any number from 0 to nearly 17 million, and store it in a compact 3-byte form (perhaps in a string array, or else in a long string), and also the inverse function, both of them doing their work in a little over 1/100th of a second, which was many times faster than the best he could do in BASIC.

Obviously, the routine can be extended to handle more or less than 3-character strings, or to include different ranges.

For instance, I have also a variation of this routine that packs numbers in the range -82.00000 to +84.77215, that is, non-integer numbers with up to 5 decimal places, in just 3 bytes. This is useful if you have a digital voltmeter connected to your 71B via HP-IL, and need to store a lot of readings from the voltmeter for later processing.

Using that modified LEX, each reading takes just 3 bytes, though it has 7-digit, 5-decimal precission.

Go back to the software library
Go back to the main exhibit hall