Repeating Decimals / Recurring Decimals - StephenG1CMZ - 01-21-2018 11:00 AM
Given an integer reciprocal, analyzes the decimal representation to identify the transient and repeating/recurring parts of the decimal.
Eg
1/3 has no transient and 3 repeats.
1/4 has transient 0.25 and no repetition.
1/7 has no transient and 0.142857 recurring.
1/14 has transient 0 and 6 recurring digits.
See http://www.hpmuseum.org/forum/thread-9919.html
For a description of the algorithms and more examples.
RE: Repeating Decimals - StephenG1CMZ - 01-21-2018 11:01 AM
(PPL) Version 0.2 follows the sequence of steps in Joe Horn's algorithm using MultiplicateOrder, which can be found here: http://www.hpmuseum.org/forum/thread-3212.html
Output is currently a list:
1: {Length of transient, transient}
2: {Length of recurring part, both parts but omitting the 0. Or 1.}
3: Just as a check, the real value.
The formatting could be improved.
Note that if the length of the recurring part exceeds 12 the recurring part returned is unreliable and should probably be replaced by NaN (the indicated length is OK, but not the digits...and sometimes they are not digits).
Code:
LOCAL CRID:="REPEATING DECIMAL (PPL) V 0.2";
//Written 2018 StephenG1CMZ
//Following Joe Horn`s algorithm using Multiplicative Order
//This implement yields some useful results but
//Large Repeating Lengths (>12repeatingdigits) yield weird output eg NN=301
//The output format could be improved.
LOCAL ImpRELEN:=12;//EMPIRICAL
LOCAL FR2,FR5;
EXPORT TESTED:={};
ZEROS(NN)
BEGIN
IF NN>0 THEN
RETURN "0"+ZEROS(NN-1);
END;
RETURN "";
END;
TRUNCRR(NN,DIGITS)
//TRUNCATE A REAL RECIPROCAL
//NN:DENOMINATOR
//DIGITS:NUMBER OF PLACES TO KEEP
BEGIN
LOCAL TP;
TP:=(1/NN)*10^DIGITS;
TP:=IP(TP)/(10^DIGITS);
RETURN TP;
END;
EXPORT 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)
BEGIN
LOCAL TRANSIENTLEN,TRANSIENTPART;
TRANSIENTLEN:=MAXFACTOR25(NN);
TRANSIENTPART:=TRUNCRR(NN,TRANSIENTLEN);
RETURN {TRANSIENTLEN,TRANSIENTPART};
END;
EXPORT ReDIGITS (NN )
//NN INTEGER
BEGIN
LOCAL TRANSIENT; //TRANSIENTLEN,TRANSIENTPART;
LOCAL WHATSLEFT,MO;
LOCAL RP,NDIGITS;
LOCAL ST;//STRINGVERSION
LOCAL RESULTS:={};
LOCAL RL;
IF NN THEN
RL:=1/NN;//DIAGNOSTIC ONLY:USUAL REAL
ELSE
RETURN {"DIVBY0"};
END;
TRANSIENT:=GETTRANSIENT(NN);
WHATSLEFT:=exact(NN/(2^FR2*5^FR5));
IF WHATSLEFT==1 THEN
//AVOID STALL
RETURN {TRANSIENT,{0,0},RL};//AVOID STALL
END;
//PRINT("BEFORE");
//See http://www.hpmuseum.org/forum/thread-3212.html
MO:=MultiplicativeOrder(WHATSLEFT,10);
//PRINT("AFTER");
NDIGITS:=TRANSIENT(1)+MO;//TRANSIENTLEN
IF MO>ImpRELEN THEN
RP:="(NaN)";
END;//FOR NOW SHOW THE WEIRD OUTPUT
RP:=iquo(1*10^NDIGITS,NN);
//The string version asks for leading zeros I hoped
//but no...pad it manually
//ST:=format(RP,"s"+NDIGITS);
ST:=ZEROS(NDIGITS-DIM(STRING(RP)))+RP;
RESULTS:={TRANSIENT,{MO,ST},RL};//
IF 0 THEN //DEBUG INFO
PRINT();
PRINT("Input Fraction: 1/"+NN+" = "+RL);
PRINT("Whats Left: "+WHATSLEFT);
PRINT("Multiplicative Order: "+MO);
//PRINT("Length: "+{TRANSIENTLEN,MO});
IF MO>12 THEN //EXPECT REPEATING PART TO GO WEIRD
PRINT("MO>12: CAUTION");
END;
PRINT("TRANSIENT PART: "+IFTE(TRANSIENT(1),TRANSIENT(2),TRANSIENT(2)+" (none)"));
PRINT(ST);
PRINT(RESULTS);
END;
//RETURN RESULTS
//TRANSIENTLEN=0 =NO TRANSIENT
//MO=0 =NO REPEATING
//MO>Imp: IGNORE REPEATING DIGITS
//RL:REAL JUST FOR COMPARISON
RETURN RESULTS;
END;
EXPORT TESTS()
BEGIN
LOCAL III,RR;
FOR III FROM 1 TO 1000 DO
//RECT_P();
//TEXTOUT_P(III,0,120);
//WAIT(2);
TESTED(0):=III;
RR:=ReDIGITS(III);
END;
END;
EXPORT REDECIMALS()
BEGIN
PRINT(CRID);
//RECT_P();
PRINT(TEVAL(TESTS));
END;
Note: A comparable CAS implementation could improve ranges handled.
Update: 99989 crashes the Android emulator.
RE: Repeating Decimals / Recurring Decimals - StephenG1CMZ - 01-24-2018 07:21 PM
Version 0.3 includes an optimised MultiplicativeOrder (base 10) and outputs a string with the recurring part annotated with an underscore (selectable).
Code:
LOCAL CRID:="REPEATING DECIMAL (PPL) V 0.3 \nCode: 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 12-15) 16 IS WRONG
LOCAL FR2,FR5;//GLOBAL RETURN
EXPORT TRANSIENTLEN;//Length of Transient
EXPORT RELEN;//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:={};
EXPORT ABOUT()
BEGIN
PRINT();
PRINT(CRID);
PRINT(ALGM);
END;
ZEROS(NN)
BEGIN
IF NN>0 THEN
RETURN "0"+ZEROS(NN-1);
END;
RETURN "";
END;
EXPORT 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 MultiplicativeOrder10(WL)
//WL: WHATSLEFT
BEGIN
LOCAL AP:=0;
LOCAL NOTFND:=1;
LOCAL LST:={};//POSSIBLES TO CHECK
IF WL≠1 THEN
//Get possibles
LST:=mat2list(idivis(euler(WL)));
//Search possiblesfor a match
WHILE AP<SIZE(LST) AND NOTFND DO
AP:=AP+1;
IF powmod(10,LST(AP),WL)==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));//TBC
END;
EXPORT GetTransient(NN)
BEGIN
LOCAL TRANSIENTPART;
TRANSIENTLEN:=MaxFactor25(NN);
IF TRANSIENTLEN THEN
TRANSIENTPART:=TRUNCATE((1/NN),TRANSIENTLEN);
ELSE
//DIVBY0 TBD
TRANSIENTPART:=IP(1/NN)+DECSEP;
END;
RETURN TRANSIENTPART;
END;
EXPORT ReDIGITS (NN )
//NN INTEGER
BEGIN
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 {"DIVBY0"};
END;
TRANSIENTPART:=GetTransient(NN);
WHATSLEFT:=exact(NN/(2^FR2*5^FR5));
IF WHATSLEFT==1 THEN
RETURN TRANSIENTPART;//AVOID STALL
END;
//See http://www.hpmuseum.org/forum/thread-3212.html
//RELEN:=MultiplicativeOrder(WHATSLEFT,10);
RELEN:=MultiplicativeOrder10(WHATSLEFT);
NDIGITS:=TRANSIENTLEN+RELEN;
IF RELEN>ImpRELEN THEN
//TBD: A better test might be to search for ᴇ in the string
ST:="(NaN)";//Implementation limit:BAD IQUO?
END;//FOR NOW SHOW THE WEIRD OUTPUT
RP:=iquo((1*10^NDIGITS),NN);
//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(RP)))+RP,TRANSIENTLEN+1);
RESULTS:=TRANSIENTPART+USCORE+ST;
//RESULTS:={{TRANSIENTLEN,TRANSIENTPART},{RELEN,ST},RL};//
IF 0 THEN //DEBUG INFO
PRINT();
PRINT("Input Fraction: 1/"+NN+" = "+RL);
PRINT("Whats Left: "+WHATSLEFT);
PRINT("Multiplicative Order: "+RELEN);
//PRINT("Length: "+{TRANSIENTLEN,RELEN});
IF RELEN>12 THEN //EXPECT REPEATING PART TO GO WEIRD
PRINT("RELEN>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 TESTS()
BEGIN
LOCAL III,RR;
FOR III FROM 1 TO 1000 DO
//RECT_P();
//TEXTOUT_P(III,0,120);
//WAIT(2);
TESTED(0):=III;
RR:=ReDIGITS(III);
END;
END;
EXPORT SHOWME()
BEGIN
LOCAL II;
FOR II FROM 1 TO 1000 DO
RECT_P();
TEXTOUT_P(II,0,20);
TEXTOUT_P(ReDIGITS(II),0,40);
WAIT;
END;
END;
EXPORT REDECIMALS()
BEGIN
ABOUT;
//PRINT((ReDIGITS(301)));
//WAIT;
//RECT_P();
PRINT(TEVAL(TESTS));
END;
Note there is a bug with the string formatting...Sometimes it includes the integer part, sometimes not.
RE: Repeating Decimals / Recurring Decimals - StephenG1CMZ - 01-26-2018 11:02 PM
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.
RE: Repeating Decimals / Recurring Decimals - StephenG1CMZ - 01-31-2018 09:10 AM
Version 0.5 is a much improved PPL program for showing transient parts and repetends of reciprocals. It has been rewritten to use CAS, enabling Transients and Repetends >12 digits to be handled, and is faster.
Code:
LOCAL CRID:="REPEATING DECIMAL V 0.5 \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
//8192 FIX TBD
LOCAL FR2,FR5;//GLOBAL RETURN
LOCAL WHATSLEFT,NDIGITS;//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 DIVBY0:="(NaN)(DIVBY0)";
MultiplicativeOrder10();//FORWARD
EXPORT ABOUT()
BEGIN
PRINT();
PRINT(CRID);
PRINT(ALGM);
END;
EXPORT HELP()
BEGIN
PRINT();
PRINT("GetLEN: Sets LENgth variables");
PRINT("Recurring/Repeating: Given integer NN, return a string of its real reciprocal with _ marking any recurring digits.");
PRINT("ShowReciprocal: Show Reciprocal");
PRINT("ShowReciprocals: Shows a range of reciprocal values.");
PRINT("Variables In: Strings DECSEP,USCORE ");
PRINT("Variables Out: RepetendLEN, TransientLEN");
PRINT("CAS: temporary variable");
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;
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(NN)
BEGIN
TransientLEN:=MaxFactor25(NN);
WHATSLEFT:=exact(NN/(2^FR2*5^FR5));
RepetendLEN:=MultiplicativeOrder10(WHATSLEFT);
NDIGITS:=TransientLEN+RepetendLEN;
//PRINT({TransientLEN,RepetendLEN});
//DO NOT INCLUDE IP LENGTH
RETURN {TransientLEN,RepetendLEN,NDIGITS};
END;
ReDIGITS (NN)
//NN INTEGER
BEGIN
LOCAL LST;//UNUSED
LOCAL ST:="";//STRINGVERSION
LOCAL STR:="";
LOCAL TRANSIENTPART,REPETEND,INTPART;
LOCAL RESULTS;
LOCAL DP;//DECIMAL PLACES
LST:=GetLEN(NN);
//GetDecimalPlaces
//RP:=iquo((1*10^NDIGITS),NN);//works for repetends≤12digits:so use CAS
CAS("temporary:=iquo((1*10^NDIGITS),NN)");
ST:=CAS("string(temporary)");
STR:=ZEROS(NDIGITS-DIM(ST));
DP:=STR+ST;
//GetRepetend
REPETEND:=IFTE(RepetendLEN,MID(DP,TransientLEN+1),"");
//GetTransientDecimalPlaces
TRANSIENTPART:=IFTE(TransientLEN,LEFT(DP,TransientLEN),"");
//Get IntegerPart
INTPART:=IFTE(NN,(IP(1/NN)+DECSEP),DIVBY0);
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(NN)
BEGIN
RETURN ReDIGITS(NN);
END;
//Some call them Recurring
//Some call them Repeating
EXPORT Repeating(NN)
BEGIN
RETURN ReDIGITS(NN);
END;
GetTransient(NN)
//NB Only when USCORE NOT EMPTY
BEGIN
LOCAL ST:=ReDIGITS(NN);
RETURN LEFT(ST,INSTRING(ST,USCORE));
END;
EXPORT ShowReciprocal(NN)
BEGIN
LOCAL PXP:={0};
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),(DIVBY0))+" Real",0,100);
TRANSIENTPART:=GetTransient(NN);
PXP(0):=TEXTOUT_P(TRANSIENTPART+" Transient Part",0,140);
PXP(0):=TEXTOUT_P(Recurring(NN)+" Decimal",0,120);
TEXTOUT_P("Has "+TransientLEN+" Transient digits & "+RepetendLEN+" Repetend digits",0,180);
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 ShowReciprocals(FIRST,LAST)
BEGIN
LOCAL NN;
FOR NN FROM FIRST TO LAST DO
ShowReciprocal(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(TESTN)
//Perform some tests
BEGIN
LOCAL III,RR;
FOR III FROM 1 TO TESTN DO
//RECT_P();
//TEXTOUT_P(III,0,120);
DRAWMENU(III);
//WAIT(2);
TESTED:=III;
RR:=ReDIGITS(III);
END;
END;
EXPORT REDECIMALS()
BEGIN
LOCAL TESTN:=1000;
ABOUT();
PRINT(TESTN+" reciprocals in "+TEVAL(TESTS(TESTN)));
//HELP();
//PRINT(Recurring(8912));
END;
There are no specific limits other than unchecked list size/CAS integer limits.
In Show, a warning is given if screen size is exceeded, but such values can still be printed.
RE: Repeating Decimals / Recurring Decimals - StephenG1CMZ - 02-01-2018 05:53 PM
Version 0.6
Show optimised. Note that the transient display assumes USCORE (underscore) is not empty.
Implementation Limits added (Some large values eg NN=1E14 exceed the limits of euler).
Code:
LOCAL CRID:="REPEATING DECIMAL V 0.6 \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("GetLEN: Sets LENgth variables");
PRINT("Recurring/Repeating: Given integer NN, return a string of its real reciprocal with _ marking any recurring digits.");
PRINT("ShowReciprocal: Show Reciprocal");
PRINT("ShowReciprocals: Shows a range of reciprocal values.");
PRINT("Variables In: Strings DECSEP,USCORE ");
PRINT("Variables Out: RepetendLEN, TransientLEN");
PRINT("Hint:To PRINT long strings,");
PRINT("PRINT(a few bytes at a time)");
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;
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(NN)
BEGIN
TransientLEN:=MaxFactor25(NN);
WHATSLEFT:=exact(NN/(2^FR2*5^FR5));
RepetendLEN:=MultiplicativeOrder10(WHATSLEFT);
NDIGITS:=TransientLEN+RepetendLEN;
//PRINT({TransientLEN,RepetendLEN});
//DO NOT INCLUDE IP LENGTH
RETURN {TransientLEN,RepetendLEN,NDIGITS};
END;
ReDIGITS (NN)
//NN INTEGER
BEGIN
LOCAL LST;//UNUSED
LOCAL ST:="";//STRINGVERSION
LOCAL STR:="";
LOCAL TRANSIENTPART,REPETEND,INTPART;
LOCAL RESULTS;
LOCAL DP;//DECIMAL PLACES
//Get Length
//A possible optimisation:
//Avoid recalc
LST:=GetLEN(NN);
//TBD:IF EXCESSIVE LENGTH RETURN NAN
//GetDecimalPlaces
//RP:=iquo((1*10^NDIGITS),NN);//works for repetends≤12digits:so use CAS
CAS("temporary:=iquo((1*10^NDIGITS),NN)");
ST:=CAS("string(temporary)");
STR:=ZEROS(NDIGITS-DIM(ST));
DP:=STR+ST;
//GetRepetend
REPETEND:=IFTE(RepetendLEN,MID(DP,TransientLEN+1),"");
//GetTransientDecimalPlaces
TRANSIENTPART:=IFTE(TransientLEN,LEFT(DP,TransientLEN),"");
//Get IntegerPart
INTPART:=IFTE(NN,(IP(1/NN)+DECSEP),DIVBY0);
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(NN)
BEGIN
RETURN ReDIGITS(NN);
END;
//Some call them Recurring
//Some call them Repeating
EXPORT Repeating(NN)
BEGIN
RETURN ReDIGITS(NN);
END;
GetTransient(NN)
//NB Only when USCORE NOT EMPTY
//NB RECALCULATES
BEGIN
LOCAL ST:=ReDIGITS(NN);
RETURN LEFT(ST,INSTRING(ST,USCORE));
END;
GetTransientToo(NN,ST)
//Requires ST to supply digits an4 USCORE
BEGIN
RETURN LEFT(ST,INSTRING(ST,USCORE));
END;
EXPORT ShowReciprocal(NN)
BEGIN
LOCAL PXP:={0};
LOCAL TRANSIENTPART;
LOCAL DST;
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("1/"+NN,0,60);
TEXTOUT_P(CAS(1/NN)+" Reduced Fraction",0,80);
TEXTOUT_P(IFTE(NN,(1/NN),(DIVBY0))+" Real",0,100);
//EARLY LENGTH
//Note:This is recalculated in ReDIGITS
GetLEN(NN);
TEXTOUT_P("Has "+TransientLEN+" Transient digits & "+RepetendLEN+" Repetend digits",0,180);
//Main Display
DST:=Recurring(NN);
//TEXTOUT_P("Has "+TransientLEN+" Transient digits & "+RepetendLEN+" Repetend digits",0,180);//IF NOT EARLY
PXP(0):=TEXTOUT_P(DST+" Decimal",0,120);
TRANSIENTPART:=GetTransientToo(NN,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 ShowReciprocals(FIRST,LAST)
BEGIN
LOCAL NN;
FOR NN FROM FIRST TO LAST DO
ShowReciprocal(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(III);
//Notethe 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+" reciprocals in "+TEVAL(TESTS(TESTN)));
//PRINT(DIM(Recurring(29989)));
//HELP();
//PRINT(Recurring(8912));
END;
Hope this is useful, although it is only implemented for reciprocals.
RE: Repeating Decimals / Recurring Decimals - StephenG1CMZ - 02-04-2018 06:46 PM
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.
RE: Repeating Decimals / Recurring Decimals - StephenG1CMZ - 02-06-2018 11:24 PM
I have noticed an issue with the step 0 fraction reduction as I have implemented it in V0.7.
In V0.6, 1/1E14 would be processed by the algorithm (no reduction being implemented).
An error message would issue from Multiplicateorder10 as implementation limits are exceeded.
In V0.7, 1/1E14 is reduced to 1E-14/1 and non-integer numerator is processed, resulting in a NaN with no error message from MultiplicativeOrder10 seen.
Potentially, there might be other values which MultiplicateOrder10 might have handled, but which are not being processed because the reduction step is introducing unexpected non-integer values.
RE: Repeating Decimals / Recurring Decimals - StephenG1CMZ - 02-07-2018 08:02 PM
Note that some long repetends incorrectly return all zeros instead of the correct digits (the reported length is correct). If you see a value with just zeros assume it is incorrect.
RE: Repeating Decimals / Recurring Decimals - StephenG1CMZ - 02-08-2018 09:03 PM
Version 0.8
Improved handling of implementation limitations.
Improved user interface shows more digits on-screen and allows long strings not to be generated.
Code:
LOCAL CRID:="REPEATING DECIMAL V 0.8 \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
LOCAL FR2,FR5;//GLOBAL RETURN
LOCAL WHATSLEFT,NDIGITS;//GLOBAL RETURN
LOCAL ImpPRINT:=2000;//PRINT LIMIT <2K
LOCAL ImpSTRING:=64000;//LIMIT VALUE TBC
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 WAITS:=0;
EXPORT ImpRELEN:=ImpSTRING;//MAX LEN TO GENERATE
EXPORT TESTED:=0;
EXPORT BigT:=0;
EXPORT BigR:=0;
LOCAL STNAN:="(NaN)";
LOCAL DIVBY0:=STNAN+"{0}";//DIVBY0
LOCAL NOTINT:=STNAN+"(NotInteger)";
LOCAL STNANImp:=STNAN+"(Imp)";//Implemenation Limit
LOCAL ImpLimST:="MultiplicativeOrder10: Implementation Limit!\n";
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("[Esc] to continue to next page");
PRINT("[View] more digits");
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: (Selectable by user @Home)");
PRINT("ImpRELEN: Recurring LEN limit");//Limit to manageable length
PRINT("String USCORE: Underscore ");
PRINT("WAITS: Show WAIT time (0=Esc)");
PRINT(" ");
PRINT("Variables Out:");
PRINT("RepetendLEN, TransientLEN");
PRINT(" ");
PRINT("Known Limitations:");
PRINT("Numbers beyond about 1/12109:");
PRINT("Repetend digits incorrectly show just 0-s (LEN OK)");
PRINT(" ");
PRINT("Hint: To PRINT long strings,");
PRINT("PRINT(a few bytes at a time)");
PRINT(" ");
PRINT("Interesting Test Values:");
PRINT("{1/: 0,1,2,3,4,7,14,208,301,8192}");
PRINT("{1/: 29989}//WRONG}");
PRINT("{1/: 3^15}//CRASH AVOIDED");
PRINT("{2/: 16384}")
END;
//STANDARD ROUTINES
DecSepNow()
//RETURN current system decimal separator
//From the forum
BEGIN
RETURN IFTE((HSeparator MOD 9)<4,".",",");
END;
//QUERY:WOULD TAKING LOGS OF NUMERATOR AND DENOMINATOR AND SUBTRACTING
//IMPROVE RANGE OR PRECISION TBD
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 GD;
LOCAL RedNUMER,RedDENOM;
IF DenomN THEN
//Step 0: Reduce Fraction
GD:=gcd(NumerN,DenomN);
RedNUMER:=NumerN/GD;
RedDENOM:=DenomN/GD;
//Continue
TransientLEN:=MaxFactor25(RedDENOM);
WHATSLEFT:=exact(RedDENOM/(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
//NEGATIVES OK
//DENOMINATOR 0: RETURN NAN
//NONINTEGER: UNCHECKED
BEGIN
LOCAL GD;
LOCAL LST;//UNUSED
LOCAL ST:="";//STRINGVERSION
LOCAL STR:="";
LOCAL TRANSIENTPART,REPETEND,INTPART;
LOCAL RESULTS;
LOCAL DP;//DECIMAL PLACES
LOCAL IPLEN;
LOCAL RedNUMER,RedDENOM;
//MSGBOX({NUMER,NN});
//GUARDS
IF NN==0 THEN
RETURN DIVBY0;
END;
IF FP(NUMER) OR FP(NN) THEN
RETURN NOTINT+STRING({NUMER,NN});//PARAMETERS NOT INTEGER
END;
IF (NUMER/NN)<0 THEN
RETURN "−"+ReDIGITS(ABS(NUMER),ABS(NN));
END;
//OK
//Step 0: reduce fraction
GD:=gcd(NUMER,NN);
RedNUMER:=NUMER/GD;
RedDENOM:=NN/GD;
//Continue...
//Get Length
//A possible optimisation:
//Avoid recalc
LST:=GetLEN(RedNUMER,RedDENOM);
//IF EXCESSIVE LENGTH RETURN NAN
IF NDIGITS>MIN(ImpRELEN,ImpSTRING-9) THEN //−9-ALLOW FOR DECSEP ETC
//STRING:TOO LONG TO GENERATE
//RELEN:USER LIMIT(TOO LONG/SLOW FOR USER)
RETURN STNANImp;
END;
//GetDecimalPlaces
//RP:=iquo((1*10^NDIGITS),NN);//works for repetends≤12digits:so use CAS
CAS("temporary:=iquo(((RedNUMER*10^NDIGITS),RedDENOM)");
ST:=CAS("string(temporary)");
//MSGBOX(ST);
STR:=ZEROS(NDIGITS-DIM(ST));
DP:=STR+ST;
//GetINTEGERPART
INTPART:=IFTE(RedDENOM,(IP(RedNUMER/RedDENOM)+DecSepNow()),DIVBY0);//THIS DIVBY IS GUARDED
//IF NUMER==1 THEN
//RECIPROCAL:iquo returns decimal places only
IF RedNUMER≠1 THEN //NN
//FRACTION: iquo returns IP and decimals with no point
IPLEN:=DIGITSNEEDED(exact(RedNUMER/RedDENOM));//LEN OF IP
DP:=MID(DP,IPLEN+1); //DP
END;
//GetRepetend
REPETEND:=IFTE(RepetendLEN,MID(DP,TransientLEN+1),"");
//GetTransientDecimalPlaces
TRANSIENTPART:=IFTE(TransientLEN,LEFT(DP,TransientLEN),"");
RESULTS:=INTPART+TRANSIENTPART+USCORE+REPETEND;
//PRINT("RESULTS: "+RESULTS);
//Imp:Sometimes the string contains source
IF INSTRING(RESULTS,"M") THEN
RESULTS:=STNANImp+RESULTS;//MARK BAD RESULT
END;
//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;
LOCAL KK,LST;
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);//NEEDS FIXING
TEXTOUT_P(IFTE(DenomN,(NumerN/DenomN),(DIVBY0))+" Real",0,100);
//EARLY LENGTH
//Note:This is recalculated in ReDIGITS
LST:=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 INSTRING(DST,"00000000000000") THEN
//Loss Of significance suspected
TEXTOUT_P(" ! Check Possible Loss Of Significance !",0,200,3,RGB(255,0,0));
END;
IF MAX(PXP)≥320 THEN //OFFSCREEN
TEXTOUT_P("[View]",320*(4/6),220,3,RGB(255,0,0));
END;
TEXTOUT_P(IFTE(WAITS>0,"Wait...","[Esc]"),320*(5/6),220,3);
KK:=WAIT(WAITS);
IF KK==9 THEN //VIEW KEY
PRINT();
PRINT(NumerN+"/"+DenomN);
PRINT(LST);
PRINT(MID(DST,1,ImpPRINT));
IF DIM(DST)>ImpPRINT THEN
PRINT("PRINT Unable");//Or:Loop
END;
//WAIT(WAITS);
END;
RETURN DST;
END;
EXPORT ShowRange(Numer1,Numer2,Denom1,Denom2)
//Show range one by one
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;
Note that some long repetends incorrectly show all zeros. These will be highlighted in Show but do not raise a NaN.
RE: Repeating Decimals / Recurring Decimals - StephenG1CMZ - 02-10-2018 11:15 PM
Version 0.9 fixes a bug caused by "exact", introduced in V0.8. Thanks for spotting that.
Error MSGBOX is improved (using an AFile to save/restore the screen).
Code:
LOCAL CRID:="REPEATING DECIMAL V 0.9 \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
LOCAL FR2,FR5;//GLOBAL RETURN
LOCAL WHATSLEFT,NDIGITS;//GLOBAL RETURN
LOCAL ImpPRINT:=2000;//PRINT LIMIT <2K
LOCAL ImpSTRING:=64000;//LIMIT VALUE TBC
EXPORT RedNUMER,RedDENOM;
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 WAITS:=0;
EXPORT ImpRELEN:=ImpSTRING;//MAX LEN TO GENERATE
EXPORT TESTED:=0;
EXPORT BigT:=0;
EXPORT BigR:=0;
LOCAL STNAN:="(NaN)";
LOCAL DIVBY0:=STNAN+"{0}";//DIVBY0
LOCAL NOTINT:=STNAN+"(NotInteger)";
LOCAL STNANImp:=STNAN+"(Imp)";//Implemenation Limit
LOCAL FL:="ZTmpMESSAGEBOX";
LOCAL ImpLimST:="MultiplicativeOrder10: Implementation Limit!\n";
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("Key [Esc] to continue to next page");
PRINT("Key [View] for more digits");
PRINT("(Do not tap)");
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: (Selectable by user @Home)");
PRINT("ImpRELEN: Recurring LEN limit");//Limit to manageable length
PRINT("String USCORE: Underscore ");
PRINT("WAITS: Show WAIT time (0=Esc)");
PRINT(" ");
PRINT("Variables Out:");
PRINT("RepetendLEN, TransientLEN//Lengths");
PRINT("RedNUMER, RedDENOM//Reduced");
PRINT("(set by GetLEN,Recurring,Repeating)");
PRINT(" ");
PRINT("Known Limitations:");
PRINT("Numbers beyond about 1/12109:");
PRINT("Repetend digits incorrectly show just 0-s (LEN OK)");
PRINT("Negative inputs may error.");
PRINT(" ");
PRINT("Hint: To PRINT long strings,");
PRINT("PRINT(a few bytes at a time)");
PRINT(" ");
PRINT("Interesting Test Values:");
PRINT("{1/: 0,1,2,3,4,7,14,208,301,8192}");
PRINT("{1/: 29989}//WRONG}");
PRINT("{1/: 1ᴇ14}//Imp");
PRINT("{1/: 3^15}//ImpCRASH AVOIDED");
PRINT("{2/: 3}");
PRINT("{2/: 16384}");
PRINT("{123/208}");
END;
//STANDARD ROUTINES
DecSepNow()
//RETURN current system decimal separator
//From the forum
BEGIN
RETURN IFTE((HSeparator MOD 9)<4,".",",");
END;
DIGITSNEEDED(NN)
//DIGITS NEEDED FOR IP
//EXCLUDES SIGN POINT SEPARATOR
BEGIN
//RETURN IP(LOG(MAX(1,ABS(NN))))+1;//PORTABLE
RETURN MAX(0,(XPON(NN)))+1;//PRIME XPON=BASE 10
END;
SCR_GET()
BEGIN
G0:=AFiles(FL)
END;
SCR_PUT()
BEGIN
AFiles(FL):=G0;
END;
ZMSGBOX(ST,OKC)
BEGIN
SCR_PUT();
OKC:=MSGBOX(ST,OKC);
SCR_GET();
RETURN OKC;
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}
//NEGATIVES:UNCHECKED
BEGIN
LOCAL GD;
IF DenomN THEN
//Step 0: Reduce Fraction
GD:=gcd(NumerN,DenomN);
RedNUMER:=NumerN/GD;
RedDENOM:=DenomN/GD;
//Continue
TransientLEN:=MaxFactor25(RedDENOM);
WHATSLEFT:=exact(RedDENOM/(2^FR2*5^FR5));
RepetendLEN:=MultiplicativeOrder10(WHATSLEFT);
NDIGITS:=TransientLEN+RepetendLEN;
//PRINT({TransientLEN,RepetendLEN});
ELSE //DIVBY0
TransientLEN:=0;
RepetendLEN:=0;
NDIGITS:=0;
END;
//NOTE: 0,0 IS OFTEN SUGGESTIVE OF AN ERROR
//BUT IS ALSO RETURNED BY 1/1
//SO MAYBE USE AN ERRORFLAG?
RETURN {TransientLEN,RepetendLEN,NDIGITS};
END;
ReDIGITS (NUMER,NN)
//Determine Digits of the fraction (NUMER/NN)
//NUMERATOR INTEGER
//DENOMINATOR INTEGER
//NEGATIVES:ATTEMPTED BUT RAISE ERROR
//DENOMINATOR 0: RETURN NAN
//NONINTEGER: RETURN NAN
BEGIN
LOCAL GD;
LOCAL LST;//UNUSED
LOCAL ST:="";//STRINGVERSION
LOCAL STR:="";
LOCAL TRANSIENTPART,REPETEND,INTPART;
LOCAL RESULTS;
LOCAL DP;//DECIMAL PLACES
LOCAL IPLEN;
//MSGBOX({NUMER,NN});
//GUARDS
IF NN==0 THEN
RETURN DIVBY0;
END;
IF FP(NUMER) OR FP(NN) THEN
RETURN NOTINT+STRING({NUMER,NN});//PARAMETERS NOT INTEGER
END;
IF NUMER<0 OR NN<0 THEN
RESULTS:=ReDIGITS(ABS(NUMER),ABS(NN));
RETURN IFTE((NUMER/NN)<0,"−"+RESULTS,RESULTS);
END;
//OK
//Step 0: reduce fraction
GD:=gcd(NUMER,NN);
RedNUMER:=NUMER/GD;
RedDENOM:=NN/GD;
//Continue...
//Get Length
//A possible optimisation:
//Avoid recalc
LST:=GetLEN(RedNUMER,RedDENOM);
//IF EXCESSIVE LENGTH RETURN NAN
IF NDIGITS>MIN(ImpRELEN,ImpSTRING-9) THEN //−9-ALLOW FOR DECSEP ETC
//STRING:TOO LONG TO GENERATE
//RELEN:USER LIMIT(TOO LONG/SLOW FOR USER)
RETURN STNANImp;
END;
//GetDecimalPlaces
//RP:=iquo((1*10^NDIGITS),NN);//works for repetends≤12digits:so use CAS
CAS("temporary:=iquo(((RedNUMER*10^NDIGITS),RedDENOM)");
ST:=CAS("string(temporary)");
//MSGBOX(ST);
STR:=ZEROS(NDIGITS-DIM(ST));
DP:=STR+ST;
//GetINTEGERPART
INTPART:=IFTE(RedDENOM,(IP(RedNUMER/RedDENOM)+DecSepNow()),DIVBY0);//THIS DIVBY IS GUARDED
//IF NUMER==1 THEN
//RECIPROCAL:iquo returns decimal places only
IF RedNUMER≠1 THEN //NN
//DEBUG;
//FRACTION: iquo returns IP and decimals with no point
IPLEN:=DIGITSNEEDED((IP(RedNUMER/RedDENOM)));//LEN OF IP
DP:=MID(DP,IPLEN+1); //DP
END;
//GetRepetend
REPETEND:=IFTE(RepetendLEN,MID(DP,TransientLEN+1),"");
//GetTransientDecimalPlaces
TRANSIENTPART:=IFTE(TransientLEN,LEFT(DP,TransientLEN),"");
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 KK,LST;
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(IFTE(DenomN,(NumerN/DenomN),(DIVBY0))+" Real",0,100);
//EARLY LENGTH
//Note:This is recalculated in ReDIGITS
LST:=GetLEN(NumerN,DenomN);
TEXTOUT_P("Has "+TransientLEN+" Transient digits & "+RepetendLEN+" Repetend digits",0,180);
TEXTOUT_P(RedNUMER+"/"+RedDENOM+" Reduced Fraction",0,80);
//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 INSTRING(DST,"00000000000000") THEN
//Loss Of significance suspected
TEXTOUT_P(" ! Check Possible Loss Of Significance !",0,200,3,RGB(255,0,0));
END;
IF MAX(PXP)≥320 THEN //OFFSCREEN
TEXTOUT_P("[View]",320*(4/6),220,3,RGB(255,0,0));
END;
TEXTOUT_P(IFTE(WAITS>0,"Wait...","[Esc]"),320*(5/6),220,3);
KK:=WAIT(WAITS);
IF KK==9 THEN //VIEW KEY
PRINT();
PRINT(NumerN+"/"+DenomN);
PRINT(LST);
PRINT(MID(DST,1,ImpPRINT));
IF DIM(DST)>ImpPRINT THEN
PRINT("PRINT Unable");//Or:Loop
END;
//WAIT(WAITS);
END;
RETURN DST;
END;
EXPORT ShowRange(Numer1,Numer2,Denom1,Denom2)
//Show range one by one
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 OKC:=0;
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
OKC:=ZMSGBOX((ImpLimST+LST),OKC);
//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;
TESTD()
BEGIN
LOCAL II;
FOR II FROM 1 TO 1000 DO
DIGITSNEEDED(123.4);
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;
Some long repetends continue to incorrectly show all zeros.
Negative fractions may now cause a MultiplicativeOrder10 error message
Update: Some values are incorrect...
|