% Calculating pi in TeX, to fit on a business card
% See the blog post for more information.
% Setup variable names
\newcount\remainder
\newcount\i
\newcount\numterms
\newcount\digit
\newcount\carry
\newcount\divisor
\newcount\index
\newcount\loopcarry
\newcount\arrval
\newcount\digits
\newtoks\currlist
\newtoks\nextlist
% Calculate #1 as the remainder of #2/#3.
\def\rem#1=#2mod#3{%
\remainder=#2%
\divide\remainder by#3%
\multiply\remainder by-#3%
\advance\remainder by#2%
#1=\remainder}
% Functions for pushing and popping from the arrays of numbers.
% Each list is stored looking like
% ;<number>;<number>;...;<number>;:
% We can then pull out the numbers between the ; and detect the
% end using the :
% Helper function for \popcurr
\def\popcurrinner;#1;#2:#3{#3=#1\global\currlist{;#2:}}
% Pops the first element of \currlist into #1
\def\popcurr#1{\expandafter\popcurrinner\the\currlist#1}
% Pushing text #1 onto nextlist or currlist
\def\pushcurr#1{%
\expandafter\global\expandafter\currlist\expandafter{%
\the\currlist #1}}
\def\pushnext#1{%
\expandafter\global\expandafter\nextlist\expandafter{%
\the\nextlist #1}}
% Calculate #1 digits of pi using the "spigot" algorithm. See
% spigot.pdf for more information about the algorithm. See
% iwriteiam.nl/SigProgC.html#pi for the C program that this
% version is based on.
\def\pid#1{%
% Given the number of digits we want, we figure out how many
% terms in the expansion we need for the digit to be correct.
% Since we're calculating in groups of 4, we need 14n/4
% terms.
\numterms=#1
\multiply\numterms by14
\divide\numterms by4
% Initialize each of the terms to 2000 by pushing that many
% terms onto the list.
\i=0
\currlist={;}%
\loop\ifnum\i<\numterms
\pushcurr{2000;}%
\advance\i by1
\repeat
\pushcurr{:}%
% Now the main loop. We repeat this until we've calculated
% all of the digits, keeping track of the carry as we go
% along.
\digit=\numterms
\loopcarry=0
\loop\ifnum\digit>0 {%
% We keep track of the carry from one term to the next
% here.
\carry=0
% Setup the list to receive the updated term remainders as
% we calculate them.
\nextlist={;}%
% Iterate through each of the terms
\i=\numterms
\loop\ifnum\i>0
% Pull the term out of the list
\popcurr\arrval
% Calculate the sum of term+carry
\multiply\carry by\i
\multiply\arrval by10000
\advance\carry by\arrval
% Calculate the divisor 2i-1
\divisor=\i
\multiply\divisor by2
\advance\divisor by-1
% The remainder goes into the next list, and the divisor
% gets carried over.
\rem\arrval=\carry mod\divisor
\expandafter\pushnext\expandafter{\the\arrval;}%
\divide\carry by\divisor
%
\advance\i by-1
\repeat
% Finish the new list and replace currlist for the next
% loop
\pushnext{:}%
\global\currlist=\nextlist
% Calculate the actual digits to show, which are the
% carry/10000 + remainder from the last loop.
\digits=\carry
\divide\digits by10000
\advance\digits by\loopcarry
% We add 10000 to the digits and then remove the leading
% 1 in \maybeaddpoint so that we don't miss leading 0s.
\advance\digits by10000
\expandafter\maybeaddpoint\the\digits%
% Calculate the remainder to carry to the next iteration
\rem{\global\loopcarry}=\carry mod{10000}%
%
\global\advance\digit by-14
}\repeat%
}
% Add a . after the first digit if this is the first group of
% digits. This turns 314159 into 3.14159. Also, add an \hfil
% in between each number so that we can break after each number
% and so we justify the digits.
\def\maybeaddpoint 1#1#2#3#4{%
#1\hfil\ifnum\digit=\numterms.\fi#2\hfil#3\hfil#4\hfil}
% Setup the page for a business card size
\pdfpagewidth=3.5in
\pdfpageheight=2in
\hsize=3in
\hoffset=-0.75in
\voffset=-0.75in
\nopagenumbers
% Actually print the output
\noindent $\pi={}$\pid{100}...\hfill~
\bye