Greedy algorithm for Egyptian fractions

From Rosetta Code
Revision as of 23:18, 2 April 2014 by rosettacode>Gerard Schildberger (added a new Rosetta Code task: Egyptian fractions.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Greedy algorithm for Egyptian fractions is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
definition

From Wikipedia, an Egyptian fraction is the sum of distinct unit fractions such as:   .

That is, each fraction in the expression has a numerator equal to 1 and a denominator that is a positive integer, and all the denominators differ from each other   (that is, none are repeated).

The (above) Egyptian fraction sums to   .

Fibonacci's Greedy algorithm for Egyptian fractions expands the fraction     to be represented by repeatedly performing the replacement

(simplifying the 2nd term in this replacement as necessary,   and

where           is the ceiling function.

This Rosetta Code task will be using the Fibonacci greedy algorithm for computing Egyptian fractions; however, if different method is used instead, please note which method is being employed.   Having all the programming examples use the Fibonacci greedy algorithm will make for easier comparison and compatible results.

Proper and improper fractions must be able to be expressed.   (See the REXX programming example to view one method of expressing the whole number part of an improper fraction.)

Improper fractions are also known as vulgar or top-heavy fractions.   See the Wikipedia article:   simple, common, vulgar fractions

task requirements
  • show the Egyptian fraction for:     and     and  
  • for all 1- and 2-digit integers, find and show an Egyptian fraction that has:
  • the largest number of terms
  • the largest denominator
  • for all 1-, 2-, and 3-digit integers (extra credit), find and show (as above).
Also see


REXX

<lang rexx>/*REXX pgm converts a fraction (can be improper) to an Egyptian fraction*/ parse arg fract; z=$egyptF(fract) /*compute the Egyptian fraction. */ say fract ' ───► ' z /*show Egyptian fraction from CL.*/ return z /*stick a fork in it, we're done.*/ /*────────────────────────────────$EGYPTF subroutine────────────────────*/ $egyptF: parse arg z 1 zn '/' zd,,$; if zd== then zd=1 /*whole #?*/ if z= then call erx "no fraction was specified." if zd==0 then call erx "denominator can't be zero:" zd if zn==0 then call erx "numerator can't be zero:" zn if zd<0 | zn<0 then call erx "fraction can't be negative" z if \datatype(zn,'W') then call erx "numerator must be an integer:" zn if \datatype(zd,'W') then call erx "denominator must be an integer:" zd _=zn%zd /*check if it's an improper fract*/ if _>=1 then do /*if improper fract, then append.*/

             $='['_"]"                /*append the whole# part of fract*/
             zn=zn-_*zd               /*now, just use the proper fract.*/
             if zn==0  then return $  /*if no fraction, we're done.    */
             end

if zd//zn==0 then do; zd=zd%zn; zn=1; end

 do  forever
 if zn==1 & datatype(zd,'W')  then return $ '1/'zd   /*append E. fract.*/
 nd=zd%zn+1;      $=$ '1/'nd          /*add unity to int fract., append*/
 z=$fractSub(zn'/'zd,  "-",  1'/'nd)  /*go and subtract the two fracts.*/
 parse var z zn '/' zd                /*extract the numerator & denom. */
 L=2*max(length(zn),length(zd))       /*calculate if we need more digs.*/
 if L>=digits()  then numeric digits L*2   /*yes, then bump the digits.*/
 end   /*forever*/                    /* [↑]  loop ends when  zn==1.   */

/*────────────────────────────────$FRACTSUB subroutine──────────────────*/ $fractSub: procedure; parse arg z.1,,z.2 1 zz.2; arg ,op

                        do j=1  for 2;   z.j=translate(z.j,'/',"_");  end

if z.1== then z.1=(op\=="+" & op\=='-') /*unary +,- first fract.*/ if z.2== then z.2=(op\=="+" & op\=='-') /*unary +.- second fract.*/

 do j=1  for 2                             /*process both fractions.   */
 if pos('/',z.j)==0     then z.j=z.j"/1";     parse var  z.j  n.j '/' d.j
 if \datatype(n.j,'N')  then call erx "numerator isn't an integer:"   n.j
 if \datatype(d.j,'N')  then call erx "denominator isn't an integer:" d.j
 n.j=n.j/1;   d.j=d.j/1                    /*normalize numerator/denom.*/
      do  while \datatype(n.j,'W');   n.j=n.j*10/1;   d.j=d.j*10/1;   end
                                           /* [↑] normalize both nums. */
 if d.j=0  then call erx "denominator can't be zero:"  z.j
 g=gcd(n.j,d.j);   if g=0  then iterate;     n.j=n.j/g;         d.j=d.j/g
 end    /*j*/

l=lcm(d.1 d.2); do j=1 for 2; n.j=l*n.j/d.j; d.j=l; end if op=='-' then n.2=-n.2 t=n.1+n.2; u=l if t==0 then return 0; g=gcd(t,u); t=t/g; u=u/g if u==1 then return t

             return t'/'u

/*═════════════════════════════general 1-line subs══════════════════════*/ erx: say; say '***error!***' arg(1); say; exit 13 gcd:procedure;$=;do i=1 for arg();$=$ arg(i);end;parse var $ x z .;if x=0 then x=z;x=abs(x);do j=2 to words($);y=abs(word($,j));if y=0 then iterate;do until _==0;_=x//y;x=y;y=_;end;end;return x lcm:procedure;y=;do j=1 for arg();y=y arg(j);end;x=word(y,1);do k=2 to words(y);!=abs(word(y,k));if !=0 then return 0;x=x*!/gcd(x,!);end;return x p: return word(arg(1),1)</lang>

output when the input used is:   43/48


43/48  ───►   1/2 1/3 1/16

output when the input used is:   5/121

5/121  ───►   1/25 1/757 1/763309 1/873960180913 1/1527612795642093418846225

output when the input used is:   2014/59

2014/59  ───►   [34] 1/8 1/95 1/14947 1/670223480

The following is a driver program to address the requirements to find the largest number of terms for a 1- or 2-digit integer, and the largest denominator.   Also, the same program is used for the 1-, 2-, and 3-digit extra credit task. <lang rexx> /*REXX pgm runs the EGYPTIAN program to find bigest denominator & #terms*/ parse arg top . /*get optional parameter from CL.*/ if top== then top=99 /*Not specified? Then use default*/ bigD=; bigT=; maxT=0; maxD=0 /*initialize some REXX variables.*/

                                      /* [↓]  determine biggest,longest*/
     do n=2      to top               /*traipse through the numerators.*/
         do d=n+1  to top             /*   "       "     " denominators*/
         fract=n'/'d                  /*create the fraction to be used.*/
         y='EGYPTIAN'(fract)          /*invoke the other REXX program. */
         t=words(y)                   /*find out how many terms in E.F.*/
         if t>maxT  then bigT=fract   /*is this a new high for # terms?*/
         maxT=max(maxT,T)             /*find the maximum number terms. */
         b=substr(word(y,t),3)        /*get the denominator from the EF*/
         if b>maxD  then bigD=fract   /*is this a new denominator high?*/
         maxD=max(maxD,b)             /*find the maximum denominator.  */
         end   /*d*/                  /* [↑]  only use proper fractions*/
     end       /*n*/                  /* [↑]  ignore  1/n  fractions.  */
                                      /* [↑]  display longest, biggest.*/

@='in the Egyptian fractions used is' /*literal to make a shorter SAY.*/ say 'largest number of terms' @ maxT "terms for" bigT say 'highest denominator' @ length(maxD) "digits is for" bigD':' say maxD /*stick a fork in it, we're done.*/</lang> output for all 1- and 2-digit integers (when using the default input):

largest number of terms in the Egyptian fractions used is 8 terms for 8/97
largest denominator in the Egyptian fractions is 150 digits is for 8/97
579504587067542801713103191859918608251030291952195423583529357653899418686342360361798689053273749372615043661810228371898539583862011424993909789665

output for all 1-, 2-, and 3-digit integers (when using for input:   -999

largest number of terms in the Egyptian fractions used is 13 terms for 529/914
largest denominator in the Egyptian fractions is 2847 digits is for 36/457