(50g) Convert Approximate to Exact for given argument
08-02-2021, 12:28 AM
Post: #1
 DavidM Senior Member Posts: 986 Joined: Dec 2013
(50g) Convert Approximate to Exact for given argument
Except for those rare occasions that I actually need to do something symbolic on my 50g, I usually have it in approximate mode. As a result, I am occasionally frustrated that I've inadvertently changed a program, list, algebraic or other object into something containing approximate numbers (reals), when it was originally intended to have contained integers. It's usually not a huge deal to change the mode and repeat whatever action is needed to obtain the desired result, but I recently decided to put together a program to do the honors instead.

The System RPL program below attempts to seek out approximate numbers contained in the object in stack level 1, and converts those which have no fractional part to an exact integer. The program contains a main procedure that is called recursively on the object whenever a composite is encountered. Most objects that it encounters along the way aren't approximate numbers, so those are simply ignored and left alone. The program considers the following objects as composites that may contain nested items, and thus "explodes" these for further processing when encountered:

- Lists
- Secondaries (programs)
- Symbolics (algebraics)
- Arrays (real and matrix, but not complex or linked arrays)
- Tagged objects

As an example, if you enter '(3*X^2+1)/19.2' on the command line while in approximate mode on a 50g, it treats all of the numbers as approximate numbers and compiles the entry as '(3.*X^2.+1.)/19.2'. Executing this program with that input will result in all of the approximate numbers that represent integers being converted to exact integers: '(3*X^2+1)/19.2'.

While I recognize that this is essentially an aid to fix my own screwups, I'm hoping that others might find a use for it as well.

The following is compilable on a 50g with the standard extable installed:
Code:
!NO CODE !RPL DEFINE   ExecR2I              LAM 'r2i EVAL DEFINE   proREAL              # 02933 DEFINE   proLIST              # 02A74 DEFINE   proSECONDARY         # 02D9D DEFINE   proSYMBOLIC          # 02AB8 DEFINE   proARRAY             # 029E8 DEFINE   proMATRIX            # 02686 DEFINE   proTAGGED            # 02AFC ::    CK1NoBlame                          ( check for 1 argument )    ( main routine [LAM 'r2i] )    ' ::       CODE          SAVE                          % get object type as BINT, leaving          A=DAT1 A                      % original object on the stack          D1=A          A=DAT1 A          GOVLNG =PUSH#ALOOP       ENDCODE       proREAL #=casedrop ::            ( real: convert to zint if integer )          DUP %FP                       ( obtain fractional part )          %0= IT FPTR2 ^R>Z             ( if fractional part is 0, convert to zint )       ;       SWAP INHARDROM? case SWAPDROP    ( if object resides in ROM, just leave )       SWAP                             ( on stack and exit )       proLIST OVER #=                  ( list|secondary|symbolic: )       OVER proSECONDARY #= OR          ( explode/process/implode )       OVER proSYMBOLIC #=       ORcase ::                        ( object is one of identified types )          SWAP                          ( leave type on stack )          INNERDUP 1LAMBIND             ( explode and save size in LAM 1 )          ZERO_DO                       ( do for each element )             ExecR2I                    ( process object )             1GETLAM ROLL               ( roll object elements )          LOOP                          ( next object )          1GETABND {}N                  ( implode stack objects to list )          SWAP CHANGETYPE               ( convert to appropriate object type )       ;       proARRAY #=casedrop ::           ( array: process contents )          DUP TYPERARRY? IT ::          ( real array? )             DUP FPTR2 ^ARSIZE 1LAMBIND ( get element count, store as LAM 1 )             FPTR2 ^XEQARRY> OBJ>R_     ( explode array )             1GETLAM ZERO_DO (DO)       ( do for each element )                ExecR2I                 ( process object )                1GETLAM ROLL            ( roll object elements )             LOOP                       ( next object )             ABND                       ( abandon LAM )             R>OBJ_ FPTR2 ^XEQ>ARRY     ( implode stack elements into array )          ;                             ( note: complex array is left unaltered )       ;                                ( by default )       proMATRIX #=casedrop ::          ( matrix: process contents )          FPTR2 ^MATRIX2LIST            ( convert matrix to list )          ExecR2I                       ( process list of lists )          FPTR2 ^LIST2MATRIX            ( convert list of lists to matrix )       ;       proTAGGED #=casedrop ::          ( tagged item: detag/process/tag )          TAG>_ SWAP                    ( extract tag, place above object )          ExecR2I                       ( process object )          SWAP >TAG                     ( re-attach tag )       ;       DROP                             ( anything else: drop type and leave )    ;                                   ( object intact )    { LAM 'r2i } BIND                   ( bind above routine to named LAM )    ExecR2I                             ( execute main routine )    ABND                                ( abandon named LAM ) ; @
02-05-2024, 01:21 AM
Post: #2
 johnb Member Posts: 242 Joined: Feb 2014
RE: (50g) Convert Approximate to Exact for given argument
(08-02-2021 12:28 AM)DavidM Wrote:  As a result, I am occasionally frustrated that I've inadvertently changed a program, list, algebraic or other object into something containing approximate numbers (reals), when it was originally intended to have contained integers.

Sorry I am so late to this party, but hopefully someone will find the following advice useful.

Having been a heavy user of an HP-48g the past couple years, I've been frustrated with accidentally clobbering a program or variable here and there. I've learned a trick:
• Global variables and programs go in {home}
• "Package" scoped variables and programs and such go in {home}/{topic}
• Do your work in {home}/{topic}/{work}

(Legend: above, underlined are literal directory names, placeholder for names are in italic.)

Topics are general packages of components. For example, I might have topics "CS", "NUMR" (numerical recipes/solutions), "INTV" (interval arithmetic), "PROJ1" and "PROJ2" (two short-term work projects).

By always working in a {work} directory, I can accidently override a global or package variable with one of my own... but I cannot accidentally overwrite one, permanently clobbering it. I just purge the offending item from {work} and try again.

And then, it's also easy to clean up after myself. I can safely purge the entire contents of my "workspace" without clobbering any of the components I'll be wanting to use there for next time.

This strategy should work for all RPL calculator series: 28, 48, 49 (all variants), and 50.

Hope this helps!

Daily drivers: 15c, 32sII, 35s, 41cx, 48g, WP 34s/31s. Favorite: 16c.
Latest: 15ce, 48s, 50g. Gateway drug: 28s found in yard sale ~2009.
 « Next Oldest | Next Newest »

User(s) browsing this thread: 1 Guest(s)