Version 0.4 has cosmetic improvements and help. It adds a CAS variable which show more digits, but I have yet to find out how use that in PPL - Whenever I try to turn it into a string, it turns into a real instead.
(Update: I have found the required syntax to do that now, so expect another release soon.)
Code:
LOCAL CRID:="REPEATING DECIMAL V 0.4 \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 implement yields useful results but
//Large Repeating Lengths (>12repeatingdigits) yield weird output eg NN=301
//NB Sometimes the leading 0. is included in the output
//but sometimes it is not...EG NN=14 Why?
LOCAL ImpRELEN:=12;//(EMPIRICAL)
LOCAL ImpTransientLEN:=12;//(EMPIRICAL)
//Should NDIGITS>12 fail?: not tested.
LOCAL FR2,FR5;//GLOBAL RETURN
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;
LOCAL STNAN:="(NaN)";
MultiplicativeOrder10();//FORWARD
EXPORT ABOUT()
BEGIN
PRINT();
PRINT(CRID);
PRINT(ALGM);
END;
EXPORT HELP()
BEGIN
PRINT();
PRINT("Recurring/Repeating: Given integer NN, return a string of its real reciprocal with _ marking any recurring digits.");
PRINT("ShowMe: Shows a range of values.");
PRINT(" ");
PRINT("Variables In: Strings DECSEP,USCORE ");
PRINT("Variables Out: RepetendLEN, TransientLEN");
PRINT("CAS: temporary variable shows more digits: Can this be used from PPL?");
PRINT("{Repetend,Transient}>12 digits: NaN implemented (PPL Limit).");
END;
ZEROS(NN)
BEGIN
IF NN>0 THEN
RETURN "0"+ZEROS(NN-1);
END;
RETURN "";
END;
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 GetTransient(NN)
//NOTE: THIS IS CALLED BY Recurring/Repeating.
BEGIN
LOCAL TRANSIENTPART;
TransientLEN:=MaxFactor25(NN);
IF TransientLEN THEN
IF TransientLEN>12 THEN
//EG NN=8192
//MSGBOX("Caution:TransientLEN= "+TransientLEN);//FIX TBC
TRANSIENTPART:="(NaN)";//IP(1/NN);//AVOID TRUNCATE
ELSE
TRANSIENTPART:=TRUNCATE((1/NN),TransientLEN);//TRUNCATE BREAKS AT 13
END;
ELSE
IF NN==0 THEN
RETURN STNAN+"DIVBY0";
END;
TRANSIENTPART:=IP(1/NN)+DECSEP;
END;
RETURN TRANSIENTPART;
END;
ReDIGITS (NN )
//NN INTEGER
BEGIN
LOCAL STR:="";
LOCAL TRANSIENTPART;
LOCAL WHATSLEFT;
LOCAL RP,NDIGITS;
LOCAL ST:="";//STRINGVERSION
LOCAL RESULTS:={};
LOCAL RL;
IF NN THEN
RL:=1/NN;//DIAGNOSTIC ONLY:USUAL REAL
ELSE
RETURN STNAN+"DIVBY0";
END;
TRANSIENTPART:=GetTransient(NN);
WHATSLEFT:=exact(NN/(2^FR2*5^FR5));
IF WHATSLEFT==1 THEN
//RETURN TRANSIENTPART;//AVOID STALL
END;
//RepetendLEN:=MultiplicativeOrder(WHATSLEFT,10);
RepetendLEN:=MultiplicativeOrder10(WHATSLEFT);
NDIGITS:=TransientLEN+RepetendLEN;
IF RepetendLEN THEN
IF RepetendLEN>ImpRELEN THEN
//TBD: A better test might be to search for ᴇ in the string
ST:=STNAN;//Implementation limit:BAD IQUO?
END;//FOR NOW SHOW THE WEIRD OUTPUT
//MSGBOX({NDIGITS,NN});
RP:=iquo((1*10^NDIGITS),NN);
//MSGBOX(RP);
CAS("temporary:=iquo((1*10^NDIGITS),NN)");
//CAS("PRINT(temporary)");
//PRINT(STR);
//The string version asks for leading zeros I hoped
//but no...pad it manually
//ST:=format(RP,"s"+NDIGITS);
ST:=ST+MID(ZEROS(NDIGITS-DIM(STRING(temporary)))+temporary,TransientLEN+1);
END;
RESULTS:=TRANSIENTPART+USCORE+ST;
IF 0 THEN //DEBUG INFO
PRINT();
PRINT("Input Fraction: 1/"+NN+" = "+RL);
PRINT("Whats Left: "+WHATSLEFT);
PRINT("Multiplicative Order: "+RepetendLEN);
//PRINT("Length: "+{TransientLEN,RepetendLEN});
IF RepetendLEN>12 THEN //EXPECT REPEATING PART TO GO WEIRD
PRINT("RepetendLEN>12: CAUTION");
END;
PRINT("TRANSIENT PART: "+IFTE(TRANSIENTLEN,TRANSIENTPART,TRANSIENTPART+" (none)"));
PRINT(ST);
PRINT(RESULTS);
END;
//RETURN RESULTS
//Return a formatted string
//(Relevant Lengths are returned globally)
RETURN RESULTS;
END;
EXPORT Recurring(NN)
BEGIN
RETURN ReDIGITS(NN);
END;
//Some call them Recurring
//Some call them Repeating
EXPORT Repeating(NN)
BEGIN
RETURN ReDIGITS(NN);
END;
EXPORT Show1(NN)
BEGIN
LOCAL TRANSIENTPART;
RECT_P();
TEXTOUT_P(CRID,0,0,3);
//TEXTOUT_P(ALGM,0,15,1);
TEXTOUT_P("Fraction,Reduced Fraction,Real,Decimal:",0,40);
TEXTOUT_P("1/"+NN,0,60);
TEXTOUT_P(CAS(1/NN)+" Reduced Fraction",0,80);
TEXTOUT_P(IFTE(NN,(1/NN)+" Real",(STNAN+"DIVBY0")),0,100);
//DEBUG;
TRANSIENTPART:=GetTransient(NN);
TEXTOUT_P(TRANSIENTPART+" Transient Part",0,140);
TEXTOUT_P(Recurring(NN)+" Decimal",0,120);
TEXTOUT_P("Has "+TransientLEN+" Transient digits & "+RepetendLEN+" Repetend digits",0,180);
TEXTOUT_P("Variable CAS.temporary may show more",0,200);
//TEXTOUT_P(CAS("temporary"),0,180);//doesnt work:PPL
TEXTOUT_P("Esc to continue",0,220);
IF RepetendLEN>ImpRELEN OR TransientLEN>ImpTransientLEN THEN
//Highlight Implement NaN
TEXTOUT_P("Imp"+STNAN,320/2,220,3,RGB(255,0,0));
END;
WAIT;
END;
EXPORT ShowMe(FIRST,LAST)
BEGIN
LOCAL NN;
FOR NN FROM FIRST TO LAST DO
Show1(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)));
//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
//Return 0 if WL=1 or no match
RETURN IFTE(NOTFND,0,LST(AP));
END;
TESTS()
BEGIN
LOCAL III,RR;
FOR III FROM 1 TO 1000 DO
//RECT_P();
//TEXTOUT_P(III,0,120);
//WAIT(2);
TESTED:=III;
RR:=ReDIGITS(III);
END;
END;
EXPORT REDECIMALS()
BEGIN
ABOUT();
PRINT(TEVAL(TESTS));
END;
The implementation returns NaN if either the Transient part or Repetend exceed 12 digits.