**HP Articles Forum**

[Return to the Index ]

[ Previous | Next ]

**"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.)

Flags3 & 4 are used to indicate various conditions throughout processing, and at least of of them will be set upon return.

Register (variable) Usagei 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 ListingLine # OP Comments 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.

Encode “read 0” vs. “read 1” as Flag 3 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 D0045 Rdn and discard

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.

Conditional Return: Half-Register 0 Read 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 D0098 Rdn and discard

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 D0108 Rdn and discard 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 D0125 STO * Z store HR1 sign in exponent work area. D0126 Rdn Discard encoded HR1 sign. D0127 E4 Shift hybrid mantissa four digits D0128 * to the left, and. D0129 FP discard HR0’s digits. 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 D0153 x <> y discard 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. D0159 x <> y discard D0160 Rdn comparand

Conditional Return: Half-Register 1 Read 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 D0198 Rdn and discard D0199 STO i restore original i value D0200 Rdn and discard

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 D0212 Rdn and discard 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 D0229 Rdn and discard 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 D0256 * incorporate HR0’s sign in HR1’s digit encoding. 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 D0283 STO i discard 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. D0294 Rdn discard comparand. 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. *