Post Reply 
50G fraction question Q-> function max denominator
11-08-2019, 05:54 PM
Post: #13
RE: 50G fraction question Q-> function max denominator
Here's one last take on the "closest fraction with power-of-2 denominator" concept.

This one uses a SysRPL implementation, and instead of requiring the maximum denominator as a given argument, that value is obtained from a global variable named "MxDen". If that variable isn't found in the current path, a new one containing a default value of 64 is created for subsequent use. As such, there is only one argument required for this program: a value to be converted (either numeric or symbolic). The final result depends on which type is given as well as the value of MxDen.

When I was playing around with this, I realized that I often wanted to go back-and-forth between the symbolic and real/approximate representations of some value. So this version evolved to function as a "toggler" between those two forms. If given a real/approximate number, it is converted to the nearest rational form. If given a symbolic, it is converted to the nearest real form. In both cases, the result is based on the currently specified maximum denominator. This means that if you give the program an argument of π with a max denominator of 64, the result will be a decimal representation of the nearest "power of 2" rational that approximates π in that range (3+9/64): 3.140625. An exact integer is treated the same as a symbolic value; the result will be that same integer in approximate form.

The source code below is appropriate for the 50g's on-board MASD compiler (ASM from menu 256), and assumes you have the HP extable installed:
Code:
!NO CODE
!ASM
   DC Z0_            273AB
!RPL
DEFINE MaxDenominator ID MxDen
::
   CK1NOLASTWD

   ( validate/create max denominator value )
   ' MaxDenominator @
   ITE ::
      ( MaxDenominator found - check validity )
      ERRSET ::
         CKREAL
         %2 %< IT ERRJMP
      ;
      ERRTRAP ::
         "Bad MxDen Value" EXITMSGSTO
         #EXITERR ERRORSTO
         ERRJMP
      ;
   ;
   ::
      ( MaxDenominator not found - store default value )
      % 64 ' MaxDenominator STO
   ;

   ( main conversion routine - placed on return stack for later processing )
   ' ::
      ( setup locals )
      DUP %0< SWAP                  ( neg )
      %ABS %>%%                     ( target )
      MaxDenominator CKREAL %>%%    ( max )
      %%2                           ( current )
      3PICK                         ( numerator )
      %%1                           ( denominator )
      DUP                           ( delta )
      {{ delta denominator numerator current max target neg }}

      ( main loop - check all denominators up to max for closest fit )
      BEGIN
         current max %%<=
      WHILE ::
         ( determine current numerator )
         current target %%*      ( multiply target number by current denominator )
         %%>% %0 RNDXY %>%%      ( round the result to the nearest integer )

         ( determine current delta )
         DUP current %%/         ( divide test numerator by current denominator )
         target %%- %%ABS        ( delta = difference between current fraction and target )

         ( if stored delta is larger, update stored values )
         delta OVER %%>
         ITE ::
            !delta !numerator
            current !denominator
         ;
            2DROP

         ( increment current denominator to next power of 2 )
         current %%2 %%* !current
        ;
      REPEAT

      ( determine c,b,a for "a+b/c" )
      numerator denominator 2%%>%
      2DUP %MOD
      ROT OVER %- 3PICK %/

      ( convert to exact integers & reorder to a,b,c )
      FPTR2 ^R>Z UNROT
      FPTR2 ^R>Z SWAP
      FPTR2 ^R>Z

      ( convert a,b,c to formatted symbolic )
      3PICK Z0_ Z= ( is a=0? )
      3PICK Z0_ Z= ( is b=0? )
      ::
         ( a & b are 0: return 0 )
         2DUP ANDcase 4DROP

         ( only a is 0: return b/c )
         2DUP NOTAND case ::
            2DROP ROTDROP
            ' x/
            BINT3 SYMBN
         ;

         ( only b is 0: return a )
         SWAP NOTAND case 2DROP

         ( otherwise return a+b/c )
         ' x/ ' x+
         BINT5 SYMBN
      ;

      ( negate if appropriate )
      neg IT ::
         DUPTYPESYMB? ITE ::
            INNERCOMP
            ' xNEG SWAP
            #1+ SYMBN
         ;
            FPTR2 ^QNeg
      ;

      ( release locals )
      ABND
   ;
   >R

   CK&DISPATCH1

   ( real/approximate number: main routine will handle )
   real
      NOP

   ( exact integer: convert to real and leave on stack without further processing )
   BINT255d ::
      FPTR2 ^Z>R
      RDROP
   ;

   ( symbolic: ->NUM, process main routine, then ->NUM again for rounded result )
   symb ::
      CRUNCH
      R> EVAL
      CRUNCH
   ;
;
@

After compiling, store the code into a named variable (I call mine "Imp" for "Imperial") and you're all set! A zipped pre-compiled version is also attached.


Attached File(s)
.zip  Imp.zip (Size: 595 bytes / Downloads: 4)
Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
RE: 50G fraction question Q-> function max denominator - DavidM - 11-08-2019 05:54 PM



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