Post Reply 
Repeating Decimals / Recurring Decimals
02-04-2018, 06:46 PM (This post was last modified: 02-05-2018 10:11 PM by StephenG1CMZ.)
Post: #7
RE: Repeating Decimals / Recurring Decimals
Version 0.7 implements handling of fractions as well as reciprocals.

Code:

 
 LOCAL CRID:="REPEATING DECIMAL V 0.7 \n©2018 StephenG1CMZ";
 LOCAL ALGM:="Following Joe Horn's algorithm: http://www.hpmuseum.org/forum/thread-9919.html";

 //Written 2018 StephenG1CMZ
 //Following Joe Horn`s algorithm using Multiplicative Order

 //This ppl implement yields useful results using CAS 
 //to provide Transients and Repetends>12  digits

 //Interesting Test Values:
 //0,1,2,3,4,7,14,208,301,8192,8912
 
 LOCAL FR2,FR5;//GLOBAL RETURN
 LOCAL WHATSLEFT,NDIGITS;//GLOBAL RETURN
 LOCAL ImpLimST:="MultiplicativeOrder10: Implementation Limit!\n";

 EXPORT TransientLEN;//Length of Transient
 EXPORT RepetendLEN;//Length of Recurring Digits/Repeating Digits
  //^Len == Decimal Digits Only
 EXPORT USCORE:="_";//CHANGE TO EMPTY STRING IF YOU WISH TO EVAL THE STRING
 EXPORT DECSEP:=".";//DECIMAL SEPARATOR (USED WHEN TRANSIENTLEN=0,IDEALLY GET FROM SYSTEM)
 EXPORT TESTED:=0;
 EXPORT BigT:=0;
 EXPORT BigR:=0;
 LOCAL DIVBY0:="(NaN)(DIVBY0)";

 MultiplicativeOrder10();//FORWARD

 EXPORT ABOUT()
 BEGIN
  PRINT();
  PRINT(CRID);
  PRINT(ALGM);
 END;

 EXPORT HELP()
 BEGIN
  PRINT();
  PRINT(CRID);
  PRINT(" Discovers characteristics of rational fractions that can be specified by an integer numerator and denominator.");
  PRINT(" ");
  PRINT("NB Fractions are input as 2 integers.\nDo not enter as Prime fractions.");
  PRINT(" ");
  PRINT("Scroll or Esc...");
  PRINT(" ");
  PRINT("API functions:");
  PRINT(" ");
  PRINT("GetLEN(fraction):");
  PRINT("Returns lengths and Sets LENgth variables.\nLengths exclude the IP and non-digits.");
  PRINT("GetLEN(1,3)={0,1}");
  PRINT(" ");
  PRINT("Recurring(fraction):");
  PRINT("Repeating(fraction):");
  PRINT("Returns a string of the real value with _ marking any recurring digits.");
  PRINT("Recurring(1,3)=0._3");
  PRINT(" ");
  PRINT("MultiplicativeOrder10(WhatsLeft):");
  PRINT("Implemented for base 10.");
  PRINT(" ");
  PRINT("Procedures:");
  PRINT(" ");
  PRINT("Show(fraction):");
  PRINT("Show Representations on_screen");
  PRINT("Show(1,3)");
  PRINT(" ");
  PRINT("ShowRange(Numer1,Numer2,Denom1,Denom2):");
  PRINT("Show Range of fractions one by one\nShowRange(1,0,3,0) = Show(1,3)");
  PRINT("ShowRange(1,2,3,4)=Show(1,3),Show(1,4),Show(2,3),Show(2,4)");
  PRINT(" ");
  PRINT("ShowReciprocals(Denom1,Denom2):");
  PRINT("Shows a range of reciprocal values one by one.\nShowReciprocals(3,0)=Show(1,3)");
  PRINT("ShowReciprocals(1,3)=Show(1,1),Show(1,2),Show(1,3)");
  PRINT("");
  PRINT("Variables In: Strings DECSEP,USCORE ");
  PRINT("Variables Out: RepetendLEN, TransientLEN");
  PRINT(" ");
  PRINT("Hint: To PRINT long strings,");
  PRINT("PRINT(a few bytes at a time)");
 END;

 //STANDARD ROUTINES
 
 DIGITSNEEDED(NN)
 //DIGITS NEEDED FOR IP
 //EXCLUDES SIGN POINT SEPARATOR
 BEGIN
  IP(LOG(MAX(1,ABS(NN))))+1;
 END;

 ZEROS(NN)
 //Recursive is faster than using CAS
 //and can output more zeros than PPL
 BEGIN
  //MSGBOX(NN);
  IF NN>0 THEN
   RETURN "0"+ZEROS(NN-1);
  END;
  RETURN ""; 
 END;
 //END STANDARD

 MaxFactor25(NN)
 BEGIN 
  LOCAL MAXFACTR:=0;
  LOCAL LST,LSTB,LP,II;
  
  LST:=mat2list(ifactors(NN)); //BASES AND COUNTSETC
  //EXTRACT BASES (2,5) ETC
  LSTB:=IFTE(SIZE(LST),MAKELIST(LST(2*II-1),II,1,(SIZE(LST)/2)),{});//{} HANDLES NN=1 
 
  FR2:=0; FR5:=0;
  LP:=POS(LSTB,2); 
  IF LP THEN
   FR2:=LST(2*LP);//EXPONENT
  END;
  LP:=POS(LSTB,5); 
  IF LP THEN
   FR5:=LST(2*LP);//EXPONENT
  END;
  
  MAXFACTR:=MAX(FR2,FR5);
  RETURN MAXFACTR;//0=NONE
 END;

 EXPORT GetLEN(NumerN,DenomN)
 //Get TransientLEN,RepetendLEN,NDIGITS
 //These lengths are decimal places and exclude IPLEN
 //0 DENOMINATOR: RETURN {0,0,0}
 BEGIN 
  LOCAL RedNUMER,RedDENOM;
  IF DenomN THEN
   //Step 0: Reduce Fraction
   RedNUMER:=CAS("numer(NumerN/DenomN)");
   RedDENOM:=CAS("denom(NumerN/DenomN)");
   IF RedNUMER≠NumerN OR RedDENOM≠DenomN THEN
    RETURN GetLEN(RedNUMER,RedDENOM);
   END;

   //Continue
   TransientLEN:=MaxFactor25(DenomN);
   WHATSLEFT:=exact(DenomN/(2^FR2*5^FR5));
   RepetendLEN:=MultiplicativeOrder10(WHATSLEFT);
   NDIGITS:=TransientLEN+RepetendLEN; 
   //PRINT({TransientLEN,RepetendLEN});
  ELSE //DIVBY0
   TransientLEN:=0;
   RepetendLEN:=0;
   NDIGITS:=0;
  END;
  RETURN {TransientLEN,RepetendLEN,NDIGITS};
 END;

 ReDIGITS (NUMER,NN)
 //Determine Digits of the fraction (NUMER/NN)
 //NUMERATOR INTEGER 
 //DENOMINATOR INTEGER
 //DENOMINATOR 0 RETURNS NAN
 BEGIN
  LOCAL LST;//UNUSED
  LOCAL ST:="";//STRINGVERSION
  LOCAL STR:="";
  LOCAL TRANSIENTPART,REPETEND,INTPART;
  LOCAL RESULTS;
  LOCAL DP;//DECIMAL PLACES
  LOCAL IPLEN;
  LOCAL RedNUMER,RedDENOM;
  //Step 0: reduce fraction
  RedNUMER:=CAS("numer(NUMER/NN)");
  RedDENOM:=CAS("denom(NUMER/NN)");
  IF RedNUMER≠NUMER OR RedDENOM≠NN THEN
   RETURN ReDIGITS(RedNUMER,RedDENOM);
  END;
  //Continue...

  //Get Length
  //A possible optimisation:
  //Avoid recalc 
  LST:=GetLEN(NUMER,NN);
    //TBD:IF EXCESSIVE LENGTH RETURN NAN

  //GetDecimalPlaces
  //RP:=iquo((1*10^NDIGITS),NN);//works for repetends≤12digits:so use CAS  
  CAS("temporary:=iquo(((NUMER*10^NDIGITS),NN)");
  ST:=CAS("string(temporary)");
  //MSGBOX(ST);
  STR:=ZEROS(NDIGITS-DIM(ST));
  DP:=STR+ST; 

  INTPART:=IFTE(NN,(IP(NUMER/NN)+DECSEP),DIVBY0); 
  //IF NUMER==1 THEN
   //RECIPROCAL:iquo returns decimal places only
  IF NN AND NUMER≠1 THEN
   //FRACTION: iquo returns IP and decimals with no point
   IPLEN:=DIGITSNEEDED(IP(NUMER/NN));//LEN OF IP
   //INTPART:=LEFT(DP,IPLEN)+DECSEP; //IP
   DP:=MID(DP,IPLEN+1); //DP
  END;
  //GetRepetend
  REPETEND:=IFTE(RepetendLEN,MID(DP,TransientLEN+1),"");
  //GetTransientDecimalPlaces
  TRANSIENTPART:=IFTE(TransientLEN,LEFT(DP,TransientLEN),"");
  //Get IntegerPart
 
  RESULTS:=INTPART+TRANSIENTPART+USCORE+REPETEND;
  //PRINT("RESULTS: "+RESULTS);
  //Return a formatted string
  //(Relevant Lengths are returned globally in ...LEN variables) 
  RETURN RESULTS;  
 END;
 
 EXPORT Recurring(NumerN,DenomN)
 BEGIN
  RETURN ReDIGITS(NumerN,DenomN); 
 END;
 //Some call them Recurring
 //Some call them Repeating
 EXPORT Repeating(NumerN,DenomN)
 BEGIN
  RETURN ReDIGITS(NumerN,DenomN);
 END;

 GetTransient(NUMER,NN)
 //NB Only when USCORE NOT EMPTY
 //NB RECALCULATES
 BEGIN
  LOCAL ST:=ReDIGITS(NUMER,NN);
  RETURN LEFT(ST,INSTRING(ST,USCORE));
 END;

 GetTransientToo(NUMER,NN,ST)
 //Requires ST to supply digits an4 USCORE
 BEGIN
  RETURN LEFT(ST,INSTRING(ST,USCORE)); 
 END;

 EXPORT Show(NumerN,DenomN)
 BEGIN
    LOCAL PXP:={0};
    LOCAL TRANSIENTPART;
    LOCAL DST;
    LOCAL RedDENOM;

    RECT_P();
    TEXTOUT_P(CRID,0,0,3);
    //TEXTOUT_P(ALGM,0,15,1);
   TEXTOUT_P("Fraction,Reduced Fraction,Real,Decimal:",0,40);
  
    // COMMON REPRESENTATIONS
    TEXTOUT_P(NumerN+"/"+DenomN,0,60);
    TEXTOUT_P(CAS(NumerN/DenomN)+" Reduced Fraction",0,80);
    TEXTOUT_P(IFTE(DenomN,(NumerN/DenomN),(DIVBY0))+" Real",0,100);

    //EARLY LENGTH
    //Note:This is recalculated in ReDIGITS
    GetLEN(NumerN,DenomN);
    TEXTOUT_P("Has "+TransientLEN+" Transient digits & "+RepetendLEN+" Repetend digits",0,180);
 
    //Main Display
    DST:=Recurring(NumerN,DenomN);
    //TEXTOUT_P("Has "+TransientLEN+" Transient digits & "+RepetendLEN+" Repetend digits",0,180);//IF NOT EARLY
  
    PXP(0):=TEXTOUT_P(DST+" Decimal",0,120);
    TRANSIENTPART:=GetTransientToo(NumerN,DenomN,DST); 
    PXP(0):=TEXTOUT_P(TRANSIENTPART+" Transient Part",0,140);
   
    IF MAX(PXP)≥320 THEN //OFFSCREEN
     TEXTOUT_P("PRINT(Recurring(NN)) may show more digits",0,200,3,RGB(255,0,0));
    END;
 
    TEXTOUT_P("Esc to continue",0,220);  
    WAIT; 
 END;

 EXPORT ShowRange(Numer1,Numer2,Denom1,Denom2)
 
 BEGIN
  LOCAL II,JJ;
  FOR II FROM Numer1 TO MAX(Numer2,Numer1) DO
   FOR JJ FROM Denom1  TO MAX(Denom2,Denom1) DO
    Show(II,JJ);
   END;
  END;
 END;

 EXPORT ShowReciprocals(FIRST,LAST)
 BEGIN
  LOCAL NN;
  FOR NN FROM FIRST TO MAX(LAST,FIRST) DO
   Show(1,NN);
  END;
 END;

 EXPORT MultiplicativeOrder10(WhatsLeft)
 //See http://www.hpmuseum.org/forum/thread-3212.html
 // WHATSLEFT
 BEGIN
  LOCAL AP:=0;
  LOCAL NOTFND:=1;
  LOCAL LST:={};//POSSIBLES TO CHECK

  IF WhatsLeft≠1 THEN
   //Get possibles
   LST:=mat2list(idivis(euler(WhatsLeft)));
   IF TYPE(LST)≠TYPE({}) THEN //EMPIRICAL TEST
    //EG NN=1ᴇ14
    MSGBOX(ImpLimST+LST);
    RECT_P();//SAVE/RESTORE IDEALLY
    //PERHAPS RETURN AND HANDLE NAN INSTEAD
    //IF NOT CAUGHT powmod WILL FAIL
   END;
   IF TYPE(LST)==TYPE({}) THEN
    //Search possiblesfor a match
    WHILE AP<SIZE(LST) AND NOTFND DO
     AP:=AP+1;
     IF powmod(10,LST(AP),WhatsLeft)==1 THEN
      NOTFND:=0;//FOUND
     END; //IF
    END;//LOOP
   END;//IF
  //Return match
  END;//VALID LST
  //Return 0 if WL=1 or no match
  RETURN IFTE(NOTFND,0,LST(AP));
 END;

 EXPORT TESTS(TESTN)
 //Perform some tests
 BEGIN
  LOCAL III,RR;
  FOR III FROM 1 TO TESTN DO
   //RECT_P();
   //TEXTOUT_P(III,0,120);
   TESTED:=III;
   RR:=ReDIGITS(2,III);
   //Note the biggest
   IF TransientLEN>BigT THEN
    BigT:=TransientLEN;
   END;
   IF RepetendLEN>BigR THEN
    BigR:=RepetendLEN;
   END;
   DRAWMENU(III,BigT,BigR);//MAX
   //DRAWMENU(III,TransientLEN,RepetendLEN);//CURRENT
  END;
 END;

 EXPORT REDECIMALS()
 BEGIN
  LOCAL TESTN:=1000;
  ABOUT(); 
  //HEADLINE RATE: LARGER WILL BE SLOWER
  PRINT(TESTN+" fractions in "+TEVAL(TESTS(TESTN)));
  //PRINT(DIM(Recurring(1,29989)));
  //HELP();
 END;

Update: use with care.
On the Android, this implementation can be problematic with larger values such as 2/16384.
Sometimes it seems to work and can return useful results, but after a Bad Argument error is reported, problems persist in the running of other programs until the calculator (not the mobile) is switched off.

Stephen Lewkowicz (G1CMZ)
https://my.numworks.com/python/steveg1cmz
Visit this user's website Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
RE: Repeating Decimals - StephenG1CMZ - 01-21-2018, 11:01 AM
RE: Repeating Decimals / Recurring Decimals - StephenG1CMZ - 02-04-2018 06:46 PM



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