begin comment **************************************************************** *** *** *** This calculation of PI uses the Bailey-Borwein-Plouffe *** *** algorithm, whereby PI = Sum [K=0 to Inf] (1/16)**K *** *** *( 4/(8*K+1) -2/(8*K+4) -1/(8K+5) -1/(8*K+6) ). *** *** At each iteration, the four arrays BFrac1 to BFrac4 are *** *** populated with the binary expansions of the fractional *** *** terms, then these are combined, and finally shifted by an*** *** amount corresponding to the factor (1/16)**K, upon which *** *** this is added to the accumulating total. Hence we get *** *** an answer of gradually increasing precision, viewable *** *** by setting bit 2 of the console word generator. *** *** *** *** Each iteration increases the precision by slightly *** *** better than 4 binary bits, so we can estimate the decimal*** *** precision correspondingly at each iteration, or otherwise*** *** by simply comparing results of consecutive iterations. *** *** *** *** Diagnostics Setting BLine causes binary dump of some *** *** =========== arrays - to see all remove the Comments *** *** Setting One on the word generator causes a *** *** trace of significant operations *** *** Setting Two on the word generator shows the *** *** decimal accumulation at EVERY iteration *** *** *** *** Author: Bob Firth *** *** Written: June,July 2010 *** *** Contact: General_Factotum@hotmail.co.uk *** *** *** *** Comment: The machine code of the 803/503 is not *** *** particularly suited to multi-word precision *** *** arithmetic, mainly because of the absence of *** *** double-length add and subtract. Nevertheless *** *** it is possible to program around this by *** *** detecting and handling overflow while processing*** *** the lower order word. *** *** *** ****************************************************************; procedure PWRDS(Ident,AStart,ASize); value AStart,ASize; integer AStart,ASize; string Ident; comment *** Dumps binary representation of elements of array *** *** starting at AStart, length 1+ASize *** ****************************************************************; begin integer BLine,NoBits,NoCHs,Count,Word; switch S ≔ PACE,LOOP,NEXT,EXIT,GETOUT; BLine ≔ 24288; Elliott(7,0,0 ,0,0,3,BLine ); Elliott(4,2,GETOUT,0,0,0,0 ); for Count ≔ step 1 until ASize do begin Elliott(7,0,0 ,0,0,3,BLine ); Elliott(4,2,EXIT ,0,0,0,0 ); PRINT(“\n”,Ident,sameline,digits(3),Count,“) ”); NOBITS ≔ 39; Elliott(3,0,AStart,0,0,4,Count); Elliott(2,0,4 ,1,3,0,0 ); Elliott(2,0,Word ,0,0,0,0 ); SPACE: PRINT(“ ”); NOCHS ≔ 2; LOOP: ELLIOTT(3,2,NoBits,0,4,2,EXIT ); if WORD < 0 then PRINT(“1”); if WORD ⩾ 0 then PRINT(“0”); ELLIOTT(3,0,Word ,0,5,5,1 ); ELLIOTT(2,0,Word ,0,4,3,NEXT ); NEXT: ELLIOTT(3,2,NoCHs ,0,4,2,SPACE ); ELLIOTT(4,0,LOOP ,0,0,0,0 ); EXIT: end; GETOUT: end PWRDS; comment ================================================================; procedure INTDV(DVDend,DIVsor,AStart,ASize); value DVDend,DIVsor,AStart,ASize; integer DVDend,DIVsor,AStart,ASize; comment *** Divides integer word DVDend by integer word DIVsor, *** *** result is stored in array ARRAY[0:ASize] *** *** where whole part of quotient goes to ARRAY[0] *** *** and fractional part populates rest of array. *** *** Array position and length given by AStart and ASize+1 *** ****************************************************************; begin integer Maxpos,One,Remain,Count,Point; switch S ≔ OTRAC,LOOP; Maxpos ≔ 74877906943; One ≔ ; Elliott(7,0,0 ,0,0,3,One ); Elliott(4,2,NOTRAC,0,0,0,0 ); PRINT(“Dividing ”,SAMELINE,DIGITS(1),DVDend,“ by ”,DIGITS(5),DIVsor); NOTRAC: Elliott(2,6,Remain,0,2,6,Count ); Elliott(3,0,AStart,0,2,0,Point ); Elliott(3,0,DVDend,0,2,0,4 ); Elliott(5,0,38 ,0,0,0,0 ); LOOP: Elliott(3,0,Remain,0,5,6,DIVsor); Elliott(0,0,Point ,1,2,0,0 ); Elliott(5,2,DIVsor,0,5,7,0 ); Elliott(0,7,4 ,0,0,3,Maxpos); Elliott(2,0,Remain,0,2,6,4 ); Elliott(2,2,Point ,0,0,0,0 ); Elliott(3,2,Count ,0,0,5,ASize ); Elliott(5,1,0 ,0,4,1,LOOP ); end INTDV; comment ================================================================; procedure COMBI(T1Strt,T2Strt,T3Strt,T4Strt,TTStrt,Max); value T1Strt,T2Strt,T3Strt,T4Strt,TTStrt,Max; integer T1Strt,T2Strt,T3Strt,T4Strt,TTStrt,Max; comment *** Take (binary fraction at) T1Strt, subtract that at T2Strt*** *** and at T3Strt and at T4Strt, and put result at TTStrt *** ****************************************************************; begin integer Maxpos,One,Count,Carry; switch S ≔ OOP,UFLO1,SKIP1,UFLO2,SKIP2,UFLO3,SKIP3,UFLO4,SKIP4; Maxpos ≔ 74877906943; One ≔ ; T1Strt ≔ 1Strt+Max; T2Strt ≔ 2Strt+Max; T3Strt ≔ 3Strt+Max; T4Strt ≔ 4Strt+Max; TTStrt ≔ TStrt+Max; Elliott(3,0,Max ,0,2,0,Count ); Elliott(2,6,Carry ,0,2,6,4 ); LOOP: Elliott(0,0,T1Strt,1,3,0,0 ); Elliott(0,0,T2Strt,1,0,5,0 ); Elliott(4,1,UFLO1 ,0,4,0,SKIP1 ); UFLO1: Elliott(0,3,MaxPos,0,2,2,4 ); SKIP1: Elliott(0,0,T3Strt,1,0,5,0 ); Elliott(4,1,UFLO2 ,0,4,0,SKIP2 ); UFLO2: Elliott(0,3,MaxPos,0,2,2,4 ); SKIP2: Elliott(0,0,T4Strt,1,0,5,0 ); Elliott(4,1,UFLO3 ,0,4,0,SKIP3 ); UFLO3: Elliott(0,3,MaxPos,0,2,2,4 ); SKIP3: Elliott(0,0,0 ,0,0,5,Carry ); Elliott(4,1,UFLO4 ,0,4,0,SKIP4 ); UFLO4: Elliott(0,3,MaxPos,0,2,2,4 ); SKIP4: Elliott(0,0,TTStrt,1,2,0,0 ); Elliott(3,6,4 ,0,2,0,Carry ); Elliott(3,0,One ,0,2,7,T1Strt); Elliott(2,7,T2Strt,0,2,7,T3Strt); Elliott(2,7,T4Strt,0,2,7,TTStrt); Elliott(0,0,0 ,0,3,7,Count ); Elliott(0,1,0 ,0,4,1,LOOP ); end COMBI; comment ================================================================; procedure SHIFT(Expone,TTStrt,SHStrt,Max); value Expone,TTStrt,SHStrt,Max; integer Expone,TTStrt,SHStrt,Max; comment *** Shift contents of array at TTStrt down by Expone*4 bits *** *** and place result at array SHStrt, both length Max *** ****************************************************************; begin integer Maxpos,One,Count,ShiftB,ShiftL,ShiftR,ShiftW,Source; switch S ≔ ONE,NOTRAC,MORE,SHIF1,NONE1,NEXT1,SHIF2,NONE2,NEXT2,NOSHIF,EXIT; Maxpos ≔ 74877906943; One ≔ ; Count ≔ xpone ÷ 19; ShiftB ≔ Expone - Count×19 )×4; ShiftW ≔ ount ×2; ShiftL ≔ hiftR ≔ ource ≔ ; if ShiftB ⩾ 60 then begin ShiftW ≔ hiftW +1; ShiftL ≔ 6 - ShiftB; goto DONE; end; if ShiftB ⩾ 40 then begin ShiftW ≔ hiftW +1; ShiftR ≔ hiftB - 38; Source ≔ ; goto DONE; end; if ShiftB ⩾ 20 then begin ShiftL ≔ 8 - ShiftB; goto DONE; end; if ShiftB ⩾ 0 then begin ShiftR ≔ hiftB; Source ≔ ; end; DONE: Elliott(7,0,0 ,0,0,3,One ); Elliott(4,2,NOTRAC,0,0,0,0 ); PRINT(“\nShift Parameters”,SAMELINE,DIGITS(3),Count,ShiftB,ShiftL,ShiftR,ShiftW,Source); NOTRAC: Elliott(0,0,0 ,0,2,6,Count ); MORE: Elliott(3,0,Count ,0,0,5,ShiftW); Elliott(4,1,NONE1 ,0,0,4,TTStrt); Elliott(2,0,4 ,1,3,0,0 ); SHIF1: Elliott(5,0,38 ,0,4,0,NEXT1 ); NONE1: Elliott(0,6,0 ,0,4,0,SHIF1 ); NEXT1: Elliott(3,0,Count ,0,0,5,ShiftW); Elliott(0,5,One ,0,4,1,NONE2 ); Elliott(0,4,TTStrt,0,0,0,0 ); Elliott(2,0,4 ,1,3,0,0 ); SHIF2: Elliott(4,0,NEXT2 ,0,0,0,0 ); NONE2: Elliott(0,6,0 ,0,0,0,0 ); NEXT2: Elliott(0,0,ShiftL,1,5,4,0 ); Elliott(0,0,ShiftR,1,5,0,0 ); Elliott(0,3,Maxpos,0,2,0,4 ); Elliott(3,0,Source,0,4,2,NOSHIF); Elliott(5,7,0 ,0,2,0,4 ); NOSHIF: Elliott(3,0,4 ,0,0,0,0 ); Elliott(0,0,SHStrt,1,2,0,0 ); Elliott(2,2,SHStrt,0,3,0,Count ); Elliott(0,4,One ,0,2,0,Count ); Elliott(0,5,Max ,0,0,5,One ); Elliott(4,1,MORE ,0,4,3,EXIT ); EXIT: end SHIFT; comment ================================================================; procedure ACCUM(BStart,BSize,TStart,TSize); value BStart,BSize,TStart,TSize; integer BStart,BSize,TStart,TSize; comment *** Add contents of extended 'integer' at BStart size BSize *** *** into extended 'integer' at TStart, size TSize. *** ****************************************************************; begin integer Maxpos,One,Count,Carry; switch S ≔ OOP,OFLO,SKIP,EXIT; Maxpos ≔ 74877906943; One ≔ ; if BSize NOTEQ TSize then begin PRINT(“\nIllegal parameters to procedure ACCUM”); goto EXIT; end; TStart ≔ Start+BSize; BStart ≔ Start+BSize; Elliott(3,0,BSize ,0,2,0,Count ); Elliott(2,6,Carry ,0,2,6,4 ); LOOP: Elliott(0,0,TStart,1,3,0,0 ); Elliott(0,0,BStart,1,0,4,0 ); Elliott(4,3,OFLO ,0,4,0,SKIP ); OFLO: Elliott(0,3,MaxPos,0,2,2,4 ); SKIP: Elliott(0,4,Carry ,0,0,0,0 ); Elliott(0,0,TStart,1,2,0,0 ); Elliott(3,6,4 ,0,2,0,Carry ); Elliott(3,0,One ,0,2,7,BStart); Elliott(0,0,0 ,0,2,7,TStart); Elliott(3,7,Count ,0,0,1,0 ); Elliott(4,1,LOOP ,0,0,0,0 ); EXIT: end CBTOD; comment ================================================================; procedure CBTOD(BStart,BSize,DStart,DSize); value BStart,BSize,DStart,DSize; integer BStart,BSize,DStart,DSize; comment *** Converts binary fraction in 'array' at BStart length *** *** 1+BSize 'to' Decimal fraction at DStart length 1+DSize *** ****************************************************************; begin integer Maxpos,Power,One,BCount,DCount,Carry,Item,Point; switch S ≔ TART,LOOP,OFLO,SKIP,EXIT; Maxpos ≔ 74877906943; Power ≔ 0000000000; One ≔ ; Elliott(3,0,DSize ,0,2,1,DCount); START: Elliott(0,6,BStart,1,1,0,0 ); Elliott(0,0,DStart,1,2,0,0 ); Elliott(3,0,DCount,0,4,2,EXIT ); Elliott(2,2,DCount,0,2,6,Carry ); Elliott(3,0,BSize ,0,2,1,BCount); Elliott(3,0,BStart,0,0,4,BSize ); Elliott(2,0,Point ,0,0,0,0 ); LOOP: Elliott(0,0,Point ,1,3,0,0 ); Elliott(5,2,power ,0,2,0,4 ); Elliott(5,7,0 ,0,0,4,Carry ); Elliott(4,3,OFLO ,0,4,0,SKIP ); OFLO: Elliott(0,3,Maxpos,0,2,2,4 ); SKIP: Elliott(0,0,Point ,1,2,0,0 ); Elliott(3,0,4 ,0,2,0,Carry ); Elliott(3,0,One ,0,2,7,Point ); Elliott(3,2,BCOUNT,0,4,1,LOOP ); Elliott(2,2,DStart,0,4,0,START ); EXIT: end CBTOD; comment ================================================================; procedure PDARY(DStart,DSize); value DStart,DSize; integer DStart,DSize; comment *** PRINT(decimal number at DStart, and fractional component *** *** at DStart+1, length DSize *** ****************************************************************); begin integer Cols,Count,Word; Cols ≔ ; Elliott(0,0,Dstart,1,3,0,0 ); Elliott(2,0,Word ,0,0,0,0 ); PRINT(“\n”,sameline,Digits(1),Word,“.”); for Count ≔ step 1 until DSize do begin Elliott(2,2,Dstart,1,3,0,0 ); Elliott(2,0,Word ,0,0,0,0 ); if ( Count-1 ) = ( ( Count-1 ) ÷ Cols )×Cols then begin if ( Count-1 ) ⩾ 1 then PRINT(“\n ”); end; PRINT(sameline,leadzero(“0”),Digits(10),Word); end; end PDARY; comment ================================================================; integer procedure ESTIM(Expone); value Expone; integer Expone; comment *** Estimate number of decimal places precision available *** *** after term Expone contributed. *** ****************************************************************; begin real Temp; Temp ≔ /(8×Expone+1)-2/(8×Expone+4)-1/(8×Expone+5)-1/(8×Expone+6); ESTIM ≔ ntier((Expone×LN(16)-LN(Temp))/LN(10)+0·5); end ESTIM; comment ================================================================; procedure TRACE(TEXT); string TEXT; comment *** Trace program flow if bit 1 set *** ****************************************************************; begin integer One; switch S ≔ OTRAC; One ≔ ; Elliott(7,0,0 ,0,0,3,One ); Elliott(4,2,NOTRAC,0,0,0,0 ); PRINT(TEXT); NOTRAC: end TRACE; comment ================================================================; procedure CALPI(MaxTrm,BMax,DMax); value MaxTrm,BMax,DMax; integer MaxTrm,BMax,DMax; comment *** Perform calculation of PI using algorithm described above*** *** MaxTrm is the number of terms to be calculated *** *** BMax is words allocated to fractional part of result *** *** DMax is words allocated (10 digits/word) to decimal *** *** part of result *** ****************************************************************; begin integer array BFrac1[0:BMax],BFrac2[0:BMax],BFrac3[0:BMax],BFrac4[0:BMax]; integer array BFracT[0:BMax],BShift[0:BMax],BReslt[0:BMax],BOutpt[0:BMax]; integer array DOutpt[0:DMax]; integer Two,Count,Term,Expone,EPlace,DWords; switch S ≔ HOW,NOSHOW; Two ≔ ; for Count ≔ step 1 until BMax do BReslt[Count] ≔ ; for Term ≔ step 1 until MaxTrm do begin Expone ≔ erm-1; PRINT(“\nAdding term ”,sameline,digits(4),Term); INTDV(4,8×Expone+1,ADDRESS(BFrac1),BMax); comment PWRDS(`BFrac1',ADDRESS(BFrac1),BMax); INTDV(2,8×Expone+4,ADDRESS(BFrac2),BMax); comment PWRDS(`BFrac2',ADDRESS(BFrac2),BMax); INTDV(1,8×Expone+5,ADDRESS(BFrac3),BMax); comment PWRDS(`BFrac3',ADDRESS(BFrac3),BMax); INTDV(1,8×Expone+6,ADDRESS(BFrac4),BMax); comment PWRDS(`BFrac4',ADDRESS(BFrac4),BMax); TRACE(“\nCombine fractions...”); COMBI(ADDRESS(BFrac1),ADDRESS(BFrac2),ADDRESS(BFrac3),ADDRESS(BFrac4),ADDRESS(BFracT),BMax); comment PWRDS(`BFracT',ADDRESS(BFracT),BMax); comment TRACE(`\nShift down...'); SHIFT(Expone,ADDRESS(BFracT),ADDRESS(BShift),BMax); PWRDS(“BShift”,ADDRESS(BShift),BMax); TRACE(“\nAccumulate...”); ACCUM(ADDRESS(BShift),BMax,ADDRESS(BReslt),BMax); comment PWRDS(`BReslt',ADDRESS(BReslt),BMax); if Term ⩾ MaxTrm-2 then goto SHOW; Elliott(7,0,0 ,0,0,3,Two ); Elliott(4,2,NOSHOW,0,0,0,0 ); SHOW: TRACE(“\nConvert to Decimal...”); for Count ≔ step 1 until BMax do BOutpt[Count] ≔ Reslt[Count]; CBTOD(ADDRESS(BOutpt),BMax,ADDRESS(DOutpt),DMax); EPlace ≔ STIM(Expone); DWords ≔ EPlace+15) ÷ 10; if DWords GR DMax then DWords ≔ Max; PRINT(SAMELINE,“ yields value for PI:-”); PDARY(ADDRESS(DOutpt),DWords); PRINT(“\nEstimated accurate to”,sameline,digits(4),EPlace,“ digits\n”); NOSHOW: end; end CALPI; comment ================================================================ ================================================================ ================================================================; begin integer N,BMax,DMax,Expone,MaxTrm; real DTB; switch S ≔ OOP1,LOOP2,ONYERBIKE; Reader(2); Punch(3); Digits(4); comment The most efficient use of array space is when both Binary and Decimal arrays hold the same precision, which occurs when DMax = BMax * ( LN(2**39)/LN(10**10)) = BMax * 1.17402 To achieve an accuracy of D decimal digits, this is guaranteed by using number of iterations given by: Maxtrm = D * ( LN(10)/LN(16) ) = D * 0.830482 where DMax decimal array entries hold 10*DMax digits For a more accurate estimate, keep increasing Expone until ( Expone*LN(16)-LN(4/(8*Expone+1)-2/(8*Expone+4)-1/(8*Expone+5)-1/(8*Expone+6)) )/LN(10) >D and then set MaxTrm :=Expone+1; Read N; if N ⩽ 0 then begin PRINT(“Invalid number”); goto ONYERBIKE; end; DMax ≔ N+9 ) ÷ 10; BMax ≔ ntier( DMax×(10×LN(10))/(39×LN(2)) )+2; PRINT(“\nRequired decimal places ”,sameline,N); PRINT(“\nArray size, Decimal storage”,sameline,DMax); PRINT(“\nArray size, Binary storage ”,sameline,BMax); PRINT(“\nOverall array space reqd. ”,sameline,DMax+8×BMax); Expone ≔ ; LOOP1: Expone ≔ xpone+10; if ESTIM(Expone) ⩽ (N-1) then goto LOOP1; LOOP2: Expone ≔ xpone-1; if ESTIM(Expone) ⩾ (N+1) then goto LOOP2; Expone ≔ xpone+1; Maxtrm ≔ xpone+1; PRINT(“\nRequired number iterations ”,sameline,Maxtrm); PRINT(“\fCalculation of PI using”,sameline,MaxTrm,“ iterations”); PRINT(“\n=======================================”,“\n”); CALPI(MaxTrm,BMax,DMax); ONYERBIKE: end; comment ================================================================; end;