 The Museum of HP Calculators

HP Articles Forum

"Double Memory" for the HP-33s

Posted by Paul Brogger on 12 Dec 2005, 6:41 p.m.

This is a program to store up to 58 half-precision values as encoded "half-registers" in HP-33s variables.

To store a value, put the value itself in stack y, and the storage location (1 <= x <= 58) in stack x, and "XEQ D". The routine stores the value, and returns the value as stored (normalized to 5 digits) in stack x.

To recall a value, put the negated storage location in stack x (-1 >= x >= -58) and "XEQ D". The routine returns the specified value in stack x.

After a "store" call, stack contents have been lost; for recall, stack y is returned in place. As written, the routine uses flags 3 & 4, but it could probably use other, more obscure flags & leave 3 & 4 to the calling programs.

The program starts mapping pseudo-registers to actual storage way up in the 6 statistics regs (half-register locations 1-12), and proceeds down to register A (half-registers 57 & 58). So if the calling routine needs a few regs, it can keep its storage low in the alphabet, and limit the range of pseudo-index values employed.

The program utilizes storage registers (variables) X, Y & Z for intermediate values, and restores the original contents of i before returning.

Potentially, similar techniques could be used to store reals of greater precision but reduced range (6 digits & 10^-9 -- 10^+9), 7-digit integers, or even more, smaller integers (perhaps as many as 87 4-digit values?)

Breaking it apart to utilize several labels would make it shorter overall, faster, and easier to understand & maintain. But I was going for the extremes.

There may be problems possible when the routine is first run against uninitialized storage registers. But once it has successfully initialized the storage areas to recognized values (say, zero), it has solidly endured literally hours of battery-draining random-value testing. (You may wish to run a loop that pre-sets all half-registers to be used, before starting your "production" routine.)

```
Half-register encoding:
Two values (ìhalf-registersî) assumed to be in scientific notation with the forms:
half-register 0			half-register 1
±a.bcde*10^±fg			±A.BCDE*10^±FG
are combined into each hybrid register value with the form:
hybrid register
±a.bcdeABCDEFG*10^±Sfg
where the digit "S" encodes the signs of half-register 1ís mantissa and exponent:
Signs in		value of
half-register 1 values	   "S"
+A.BCDE*10^+FG		    0
-A.BCDE*10^+FG		    1
+A.BCDE*10^-FG	            2
-A.BCDE*10^-FG		    3
Half-registers have five digits of precision, and may assume any positive or negative value with magnitude in the range
1.0000 * 10^-99  <=  n <=  9.9999 * 10^99
(Exception:  To insure the encoding works consistently, the value  -1.0000*10^-99 is used to encode zero.)
Flags 3 & 4 are used to indicate various conditions throughout processing, and at least of of them will be set upon return.
Register (variable) Usage
i index	       name   user index	Use(s)
01 - 23	      A - W    58 - 13		storage ñ two half-register values in each
24		X	 - -		half-register 0
(-9.9999*10^99 <= n<= 9.9999*10^99)
25		Y	 - -		half-register 1
(-9.9999*10^99 <= n<= 9.9999*10^99)
26		Z	 - -		storage location and exponents work area
27		i	 - -		index register (for indirect addressing of other regs)
28 - 33	    stat regs	12-01		storage ñ two half-register values in each
Program Listing
D0001	LBL  D		ìDblMemî ñ HP-33s ìDouble Memoryî subroutine
Normalize and Store Callerís Index Specification
D0002	CF  4		if set, exit after extracting half-register 1
D0003	x < 0?		if x negative, ìrecallî requested
D0004	SF  4		so indicate such with flag # 4
D0005	ABS			now that sign has been encoded, get rid of it
D0006	IP				and insure only integer value
D0007	1		minimum value for pseudo-index
D0008	x > y?		    if caller specified a lower value
D0009	x <> y			use 1.
D0010	Rdn
D0011	58		maximum value for pseudo-index
D0012	x < y?		    if caller specified a higher value
D0013	x <> y			use 58.
D0014	Rdn
D0015	68		Map index specified
D0016	x <> y		    to storage available
D0017	-		       by first ìreversingî it and adding 9.
D0018	CF  3		If set, pseudo-index will not require adjustment
D0019	56		pseudo-index of 1st stats register
D0020	x <= y?		    If caller specified that or greater
D0021	SF  3			then signal no later adjustment necessary
D0022	Rdn
D0023	8		Pseudo-index gap for ìsystemî registers X, Y, Z & i
D0024	FS?  3		Is userís index at or beyond 1st statistics register?
D0025	CL x		    then no adjustment necessary.
D0026	-			Shift lower storage values below X.
D0027	100	         Shift exponent two digits
D0028	˜	             to the right of the decimal point
D0029	STO  Z			 and store pseudo-index (as fractional portion) in work area.
D0030	CF  3		if set, exit after extracting half-register 1
D0031	FS?  4		is this to be a read operation?
D0032	SF  3		    if so, we might want to exit early
D0033	0.02		Divide by two and multiply by 100
D0034	RMDR		    so  |x| mod 2 (ìeven or oddî) indicates which desired
D0035	x > 0?		x non-zero?  (i.e., ìoddî?)
D0036	CF  3		    if so, exit only after extracting half-register 1.
D0037	Rdn
Obtain Hybrid Value  from  Indicated Register
D0038	RCL  Z		obtain callerís pseudo-index value again
D0039	0.02		    divide by 2 (& multiply by 100)
D0040	INT ˜			translating to actual index number
D0041	x <> i		swap with calculatorís index register.
D0042	RCL  (i)	    obtain the indicated hybrid storage value
D0043	x <> y		restore original i value
D0044	STO  i		    to minimize overall impact
Extract Half-Register 0  from  Hybrid in x
D0046	ENTER		    copy to y for later
D0047	ABS			insure that itís positive
D0048	x ^= 0?		x non-zero?
D0049	LOG		    obtain LOG so we can get at
D0050	INTG			the exponent (characteristic)
D0051	SGN		-1, 0 or 1 for adjustment
D0052	x ^= 0 ?	If value won't wipe out the fractional portion,
D0053	STO * Z		    incorporate it in the exponent work area
D0054	Rdn
D0055	LAST x		full characteristic (sign + magnitude)
D0056	STO + Z		    can now be stored, maintaining fractional portion.
D0057	10^x		raise as power of ten
D0058	˜		    and remove from original hybrid value
D0059	E4	        Shift resulting mantissa
D0060	*		    four digits to the left.
D0061	IP		Get rid of half-register 1ís digits
D0062	E4		    and shift four digits
D0063	˜			back to the right.
D0064	RCL  Z		Obtain normalized hybrid exponent and pseudo-index
D0065	IP		    Get rid of pseudo-index (fractional portion)
D0066	E2		Shift exponent value
D0067	˜		    two digits to the right.
D0068	FP		Get rid of half-register 1ís signs
D0069	E2		    and shift two digits
D0070	*			back to the left.
D0071	10^x		Raise as power of ten
D0072	*	            and finish extraction of half-register 0ís value.
Substitute Special Value if Zero
D0073	-1E-99		DblMemís special encoding of ìzeroî
D0074	x <> y		    swap with recovered HR0 value
D0075	x = 0 ?		Recovered value equal to zero?
D0076	x <> y		    then store encoded value instead.
D0077	STO  X		Store extracted half-register 0 value in X
D0078	x <> y		    and clear comparand
D0079	Rdn			from stack.
Handle Encoded Zero, Returning Zero Itself
D0080	-1E-99		DblMemís encoding of value ìzeroî
D0081	x <> y		    swap with stored HR0 value
D0082	x = y ?		Stored HR0 value equal to encoded zero?
D0083	CL x		    Then return actual zero value
D0084	x <> y			and clear comparand
D0085	Rdn			    from stack.
D0086	FS?  3		If the caller wanted half-register 0,
D0087	RTN		    return
Continue, Obtaining Half-Register 1
D0088	Rdn		Clear stack of half-register 0 value
Obtain Hybrid Value from Indicated Register
D0089	RCL  Z		obtain callerís pseudo-index value again
D0090	ABS		    Remove exponent's sign
D0091	FP			and its digits, leaving fractional index value
D0092	0.02		Divide by 2 (& multiply by 100)
D0093	INT ˜               translating to actual index number
D0094	x <> i		swap with calculatorís index register.
D0095	RCL  (i)	    obtain the indicated hybrid storage value
D0096	x <> y		restore original i value
D0097	STO  i		    to minimize overall impact
Extract  Half-Register 1  from  Hybrid in x
D0099	ABS		    Donít need hybridís sign for HR1
D0100	RCL  Z		First, obtain hybridís exponent.
D0101	IP		    reduce to exponent itself;
D0102	10^x		Raise as power of ten
D0103	˜		    and remove from hybrid value.
D0104	RCL  Z		Obtain hybrid exponent again
D0105	ABS		    donít need sign of hybridís exponent anymore
D0106	FP			nor its digits
D0107	STO  Z		Save pseudo-index value for later
D0109	LAST x		full characteristic (sign + magnitude)
D0110	IP		    (stripped of fractional index)
D0111	E2		shift two places
D0112	˜		     to the right, and
D0113	IP			reduce to HR1ís encoded signs.
D0114	2		HR1ís sign-of-exponent encoded in hundreds digit.
D0115	CF  3		Use flag 3 now to indicate sign of HR1ís exponent.
D0116	x <= y ?	If  y >= 2,  then
D0117	SF  3		    sign of HR1 exponent is negative.
D0118	x > y ?		If  y < 2,  then
D0119	CL x		    donít subtract out HR1ís sign of exponent.
D0120	-		Reduce to HR1 sign of value.
D0121	SGN		    Insure value is either 1 or 0.
D0122	+ / -		        Negate if anything left.
D0123	x = 0?		If HR1 is to be positive
D0124	10^x		    create a positive 1, and
D0126	Rdn		            Discard encoded HR1 sign.
D0127	E4		Shift hybrid mantissa four digits
D0128	*		    to the left, and.
D0130	E5		Shift HR1ís digits 5 places
D0131	*		    to the left, and
D0132	IP			obtain HR1ís mantissa
D0133	LAST x		Restore all HR1 digits
D0134	FP		    and obtain exponent.
D0135	E2		Shift exponent two places
D0136	*		     to the left,
D0137	IP			(insure no fractional portion) and
D0138	FS  3?			(BTW, if flag 3 was set above,
D0139	+ / -				then HR1 exponent is negative)
D0140	10^x		raise as power of ten.
D0141	x <> y		Swap exponent and mantissa,
D0142	E4		    shift mantissa four digits
D0143	˜			to the right, and
D0144	*			    combine HR1 mantissa and exponent.
D0145	RCL  Z		and finally,
D0146	SGN		    reimpose HR1ís
D0147	*			sign.
Substitute Special Value if Zero
D0148	-1E-99		DblMemís encoding of value ìzeroî
D0149	x <> y		    swap with recovered HR1 value
D0150	x = 0 ?		Recovered value equal to zero?
D0151	x <> y		    then store encoded value instead.
D0152	STO  Y		Store extracted half-register 1 value in Y
D0154	Rdn			comparand
Handle Encoded Zero, Returning Actual Zero
D0155	-1E-99		DblMemís encoding of value ìzeroî
D0156	x <> y		     swap with actual HR1 value
D0157	x = y ?		Actual value equal to encoded zero?
D0158	CL x		    Then make it so.
D0160	Rdn			    comparand
D0161	CF  3		    (clean up the other flag we used)
D0162	FS?  4		If the caller wanted half-register 1,
D0163	RTN		    return
Continue, Storing New Half-Register Value Supplied as y
D0164	Rdn		Clear stack of HR1 value, moving original y to x
Normalize Callerís  y  Value for Storage
D0165	-1E-99		Encoded value for zero.
D0166	x <> y		Swap with actual value
D0167	x = 0 ?		    and if that value is indeed zero,
D0168	x <> y			then use our encoded substitute.
D0169	x <> y		Clean up ñ keeping the stored, normalized value
D0170	Rdn		    and discard the other, unstored alternative.
D0171	x < 0 ?		Encode sign of stack y value
D0172	SF  3		    in flag # 3.
D0173	ABS		Ignore the supplied valueís sign, for now.
D0174	SCI  4		Set display to precision weíll be supporting
D0175	RND		    and enforce that precision on userís value.
D0176	9.9999E99	Upper bound of supported range
D0177	x < y ?		    If supplied value is beyond that
D0178	x <> y			then substitute upper bound
D0179	Rdn
D0180	+1E-99		Lower bound of supported range.
D0181	x > y ?		    If supplied value is less than that
D0182	x <> y			then substitute lower bound
D0183	Rdn
D0184	FS?  3		Get original stack y sign
D0185	+ /-		    and reimpose on our normalized value.
Overwrite Appropriate Restored HR with New  y  Value
D0186	RCL  Z		obtain callerís pseudo-index value / exponent again
D0187	ABS		    we can ignore the exponent's sign
D0188	FP			and fractional portion is what we're interested in
D0189	STO  Z		keep callerís pseudo-index value only, for now
D0190	0.02		     divide by 2 (& multiply by 100)
D0191	RMDR		Reduce to an ìeven or oddî flag
D0192	SGN		    indicated by zero or one
D0193	24			and calculate
D0194	+			    the actual index value (to variable X or Y).
D0195	x <> i		swap with calculatorís index register.
D0196	x <> y		set aside original i value
D0197	STO  (i)	    update X or Y, as indicated
D0199	STO  i		restore original i value
Synthesize New  HR0-HR1 Hybrid  for Storage
D0201	RCL  Y		HR1's value
D0202	CF  3		Clear ìHR1 sign is negativeî flag
D0203	x < 0 ?		    if HR1 is less than 0,  then
D0204	SF  3			HR1ís sign is negative.
D0205	ABS		insure that itís positive
D0206	x ^= 0 ?	    if HR1 is non-zero,  then
D0207	LOG			obtain LOG so we can get at
D0208	INTG			    the characteristic
D0209	SGN			(first, weíll need its sign)
D0210	x ^= 0 ?	if HR1 is non-zero,  then
D0211	STO * Z		    store HR1's sign of exponent on fractional index
D0213	LAST x		so that now, full characteristic
D0214	STO + Z		    may be added without corrupting fractional index.
D0215	CF  4		Clear ìHR1 exponent is negativeî flag
D0216	x < 0 ?		    if HR1 exp is less than 0,  then
D0217	SF  4			HR1ís exp is negative.
D0218	Rdn
D0219	RCL  Y		Obtain HR1 value
D0220	ABS		    eliminate sign (encoded above as flag 3).
D0221	RCL  Z		Obtain HR1ís
D0222	IP		    exponent value
D0223	10^x		Raise as power of ten
D0224	˜		    and remove from HR1ís original value
D0225	RCL  Z		Obtain exponent / index storage value
D0226	ABS		    Remove exponent's sign
D0227	FP			and its digits.
D0228	STO  Z		Update work register for now
D0230	LAST x		Restore full work register value
D0231	IP		    and consider the exponent
D0232	E6		Shift six places
D0233	˜		    to the right
D0234	+			and tack onto the end of HR1ís mantissa.
D0235	STO  Y		Place HR1ís encoded value in its original storage
D0236	Rdn		    and discard (for now).
D0237	RCL  X		Read the HR0 value
D0238	ABS		    insure that itís positive
D0239	x ^= 0 ?	If HR0 is non-zero,  then
D0240	LOG		    obtain LOG so we can get at
D0241	INTG			the exponent (characteristic).
D0242	SGN		-1, 0 or 1 for adjustment value
D0243	x ^= 0 ?	If resulting value won't obliterate fractional index
D0244	STO * Z		    go ahead and save it.
D0245	Rdn
D0246	LAST x		Full characteristic again
D0247	STO + Z		    store as integer portion of work register.
D0248	5		Shift that exponent five digits
D0249	-		    to the right,
D0250	10^x		Raise as a power of ten, and
D0251	RCL * Y		    incorporate in  HR1ís encoding
D0252	RCL  X		Get HR0's value
D0253	SGN		    to utilize its sign
D0254	x = 0 ?		if HR0 is zero,  then
D0255	10^x		    make it one
D0257	STO + X		    & append HR1ís encoded digits to HR0
D0258	Rdn
D0259	E2		HR1ís signs are encoded in the hybrid exponentís 100ís digit
D0260	RCL  Z		Obtain HR0ís exponent
D0261	IP		    to maintain
D0262	SGN			its sign
D0263	x = 0 ?		    (if HR0 exponent is zero,  then
D0264	10^x			make it ìpositiveî)
D0265	*		    in the upcoming encoding operations.
D0266	10^x		Raise as power of ten
D0267	FS  3?		If HR1ís sign is negative,
D0268	STO * X		    add ±100 to the hybridís exponent.
D0269	x≤			Double the exponent code value
D0270	FS  4?		If HR1ís exponent sign is negative,
D0271	STO * X		    add ±200 to the hybridís exponent.
D0272	Rdn
D0273	RCL  X		Recall the newly-synthesized hybrid value.
Store Updated Hybrid in x Into Appropriate Register
D0274	RCL  Z		obtain callerís half-register index again
D0275	ABS		    we can ignore the exponent's sign
D0276	FP			and fractional portion is what we're interested in
D0277	0.02		divide by 2 (& multiply by 100)
D0278	INT ˜		    translating to actual index number
D0279	x <> i		swap with calculatorís index register.
D0280	x <> y		set aside original i value
D0281	STO  (i)	    update storage register with new hybrid value
D0282	Rdn
D0284	Rdn			    original i value
Initiate Recall of Newly-Stored Value
D0285	RCL  Z		Obtain pseudo-register index
D0286	ABS		    without exponent's sign
D0287	FP			or digits.
D0288	E2		Shift two digits
D0289	*		    to the left,
D0290	56			and compare to lowest index for stat registers
D0291	CF  3		Initialize ìadjustment neededî flag
D0292	x <= y ?	Pseudo-index points to stat regs?
D0293	SF  3		    then no need to make an alteration.
D0295	8		Adjustment value ñ bypass X, Y, Z & i
D0296	FS?  3		    Is adjustment necessary?
D0297	CL x			no.
D0298	+		Undo adjustment (if any) performed at entry.
D0299	68		Pseudo-register reversal
D0300	-		   gives ìrecallî value as if supplied by user.
D0301	FIX  2		Restore (my) preferred display mode
D0302	GTO  D		    and go read specified value.
MEM usage:	1338
Checksum:	CA99
```

If you've any questions or corrections, try the Forum, or take the "NoHormel" out of my email address & get to me.

Enjoy!

-- Paul B. 12/12/2005

Edited: 2 June 2006, 10:09 a.m.