Madoka Kaname

Magical girl who does programming and math. My username is sayurc everywhere but you can call me Sayu.


Spigot Algorithms

Introduction

Recently I was talking with my girlfriend about how her unit calculator tool, Rink, calculates π\pi. This reminded me of some algorithms that are not very well known but are very interesting, so I decided to search about them more but I couldn't find much information apart from a section in a Wikipedia article and a few research papers. So I'm writing this post to condense all the information I could find or derive myself, explaining everything as thoroughly as it is reasonable in the hope it will be interesting.

There are many widely known methods for approximating π\pi and other important irrational numbers with infinite series, continued fractions or other procedures involving limits. The following alternating series was independently discovered by Madhava of Sangamagrama in the 14-th century, James Gregory in 1671 and Gottfried Leibniz in 1673 and is known as the Leibniz formula for π\pi

π4=k=0(1)k2k+1.\frac{\pi}{4} = \sum_{k = 0}^\infty \frac{(-1)^k}{2k + 1}.

How good is this formula for approximating π\pi? Sadly, not very good, as it needs five thousand terms just to get four decimal places and literally billions of terms for ten decimal places. In constrast, Ramanujan's formula for π\pi converges extremely fast:

1π=229801k=0(4k)!(1103+26390k)(k!)43964k.\frac{1}{\pi} = \frac{2\sqrt{2}}{9801}\sum_{k = 0}^\infty\frac{(4k)!(1103 + 26390k)}{(k!)^{4}396^{4k}}.

Indeed, it is so fast that it only needs one term to calculate π\pi up to six decimal places and two terms for fifteen. This formula is an example of a Ramanujan-Sato series which are the basis of the Chudnovsky algorithm, an extraordinarily fast algorithm for calculating π\pi, used for many record breaking computations of up to 202 trillion digits in 2024 using y-cruncher, a very well optimized program that computes π\pi and other constants.

Although these series converge really fast, they all suffer from two problems:

The second problem may sound very esoteric, you may have never considered that it is even possible to extract any arbitrary digit of an irrational number without calculating previous digits, but I will soon show how this is, very surprisingly, actually possible. As for the first problem, there is a way to compute π\pi digit by digit without any floating point operations, but it won't be faster than an algorithm like Chudnovsky's due to slower convergence.

We call algorithms that approximate a number digit by digit spigot algorithms, and if the algorithm also allows the digits to be calculated without first calculating the earlier digits it is a digit extraction algorithm. Before presenting a spigot algorithm for π\pi I will first use Euler's number as an example of how we can construct such algorithms since it is easier than the algorithm for π\pi.

The Idea

Euler's number is defined as

e=limn(1+1n)n.e = \lim_{n \to \infty} \left(1 + \frac{1}{n}\right)^n.

Euler proved that

e=n=01n!=10!+11!+12!+13!+14!+e = \sum_{n = 0}^\infty \frac{1}{n!} = \frac{1}{0!} + \frac{1}{1!} + \frac{1}{2!} + \frac{1}{3!} + \frac{1}{4!} + \cdots

and we can rewrite this as

e=2+12(1+13(1+14(1+))).e = 2 + \frac{1}{2}\left( 1 + \frac{1}{3}\left( 1 + \frac{1}{4}\left( 1 + \cdots \right)\right)\right).

We know that 22 is the integer part of ee so of course the remaining expression is its fractional part, which means we can multiply it by 1010 to shift the next digit to the integer part. For this example it is enough to use only six terms:

10e20+12(10+13(10+14(10+15(10+16(10))))).10e \approx 20 + \frac{1}{2}\left( 10 + \frac{1}{3}\left( 10 + \frac{1}{4}\left( 10 + \frac{1}{5}\left( 10 + \frac{1}{6}\left( 10 \right)\right)\right)\right)\right).

a/b=q+r/ba/b = q + r/b for any integer a,ba,b where qq is the quotient and rr the remainder so we can apply this to all the fractions from right to left like this:

10e20+12(10+13(10+14(10+15(11+16(4)))))=20+12(10+13(10+14(12+15(1+16(4)))))=20+12(10+13(13+14(0+15(1+16(4)))))=20+12(14+13(1+14(0+15(1+16(4)))))=27+12(0+13(1+14(0+15(1+16(4)))))(1)\begin{equation} \begin{split} 10e &\approx 20 + \frac{1}{2}\left( 10 + \frac{1}{3}\left( 10 + \frac{1}{4}\left( 10 + \frac{1}{5}\left( 11 + \frac{1}{6}\left( 4 \right)\right)\right)\right)\right)\\ &= 20 + \frac{1}{2}\left( 10 + \frac{1}{3}\left( 10 + \frac{1}{4}\left( 12 + \frac{1}{5}\left( 1 + \frac{1}{6}\left( 4 \right)\right)\right)\right)\right)\\ &= 20 + \frac{1}{2}\left( 10 + \frac{1}{3}\left( 13 + \frac{1}{4}\left( 0 + \frac{1}{5}\left( 1 + \frac{1}{6}\left( 4 \right)\right)\right)\right)\right)\\ &= 20 + \frac{1}{2}\left( 14 + \frac{1}{3}\left( 1 + \frac{1}{4}\left( 0 + \frac{1}{5}\left( 1 + \frac{1}{6}\left( 4 \right)\right)\right)\right)\right)\\ &= 27 + \frac{1}{2}\left( 0 + \frac{1}{3}\left( 1 + \frac{1}{4}\left( 0 + \frac{1}{5}\left( 1 + \frac{1}{6}\left( 4 \right)\right)\right)\right)\right)\\ \end{split} \end{equation} \qquad \mathrm{(1)}

and, indeed, 77 is the next digit of ee. You can repeat this procedured as many times as you want and it will keep producing more digits as long as you use enough terms. In general, if we have a number defined by a recursive sum of the form

a=a0+12(a1+13(a2+14(a3+)))(2)\begin{equation} a = a_0 + \frac{1}{2}\left( a_1 + \frac{1}{3}\left( a_2 + \frac{1}{4}\left( a_3 + \cdots \right)\right)\right) \end{equation} \qquad \mathrm{(2)}

we can apply this method to produce aa digit by digit, a0a_0 is always its integer part and the rest of the recursive sum is its fractional part. So, by induction, if we apply the procedure above we will get the next digit d1d_1 so the integer part of 10a10a is a0d1a_0d_1 and the rest of the expression is the fractional part, whose first digit is of course the second digit of aa. So we can keep applying this procedure to generate aa digit by digit. Hopefully you can see this pattern by looking at the example. And as it turns out, computers are very good at patterns!

However, this is not necessarily true for the most general case when the recursive sum is not of the above form. In a sum with different fractions it is possible that the sum after a0a_0 is not always the fractional part. For example, a similar formula for π\pi is

π=2+13(2+25(2+37(2+)))(3)\begin{equation} \pi = 2 + \frac{1}{3}\left( 2 + \frac{2}{5}\left( 2 + \frac{3}{7}\left( 2 + \cdots \right)\right)\right) \end{equation} \qquad \mathrm{(3)}

and of course 22 is not the integer part of π\pi, so the rest of the sum still contributes to the integer part. In fact, after we get some number of digits the remaining sum will again contribute to the last digit we produced. This is the complication I mentioned in the Introduction section and we will see how to deal with it later.

In the next section I will formalize the idea presented above and prove that it works as expected for sums of the form (*).

Generalizing Number Bases

We are all used to numbers written in base 10, such as 17291729, 277777788888899277777788888899 and 5.285714285715.28571428571, and I believe many of you are also fluent in base 2 and base 16. In general, for an integer b>1b > 1 then we have a positional numeral system of base bb where a string of digits dnd2d1d0.d1d2d3d_n \dots d_2d_1d_0.d_{-1}d_{-2}d_{-3} \dots represents the number

dnbn++d2b2+d1b1+d0b0+d1b1+d2b2+d3b3+.(4)d_nb^n + \cdots + d_2b^2 + d_1b^1 + d_0b^0 + d_{-1}b^{-1} + d_{-2}b^{-2} + d_{-3}b^{-3} + \cdots. \qquad \mathrm{(4)}

and when di<bd_i < b for all ii we say that the representation is regular. This representation does not need to be unique. To see this, let's write 0.999...0.999... as

0.9=k=1910k,0.\overline{9} = \sum_{k = 1}^{\infty} \frac{9}{10^k},

which follows from the definition given above. We also have the inequality

01k=0n910k110n.0 \leq 1 - \sum_{k = 0}^n \frac{9}{10^k} \leq \frac{1}{10^n}.

Since limn1/10n=0\lim_{n \to \infty} 1/10^n = 0, by the squeeze theorem

1k=0910k=limn(1k=0n910k)=0.1 - \sum_{k = 0}^\infty \frac{9}{10^k} = \lim_{n \to \infty} \left(1 - \sum_{k = 0}^n \frac{9}{10^k}\right) = 0.

Therefore 0.9=10.\overline{9} = 1. And the same is true for any other base, 0.1=10.\overline{1} = 1 in binary and 0.F=10.\overline{F} = 1 in hexadecimal.

Rewriting (4) as

d0+b(d1+b(d2+b(+b(dn))))+b1(d1+b1(d2+b1(d3+b1())))d_0 + b(d_1 + b(d_2 + b(\cdots + b(d_n)))) + b^{-1}(d_{-1} + b^{-1}(d_{-2} + b^{-1}(d_{-3} + b^{-1}(\cdots))))

gives us a way to generalized numeral systems. Instead of having a base based on a fixed bb, we can use any numbers for each bb and b1b^{-1} in the above expression, giving us

d0+b1(d1+b2(d2+b3(+bn(dn))))+1b1(d1+1b2(d2+1b3(d3+)))d_0 + b_1(d_1 + b_2(d_2 + b_3(\cdots + b_n(d_n)))) + \frac{1}{b_{-1}}\left(d_{-1} + \frac{1}{b_{-2}}\left(d_{-2} + \frac{1}{b_{-3}}\left(d_{-3} + \cdots\right)\right)\right)

where ,b3,b2,b1,b1,b2,b3,,bn\dots, b_{-3}, b_{-2}, b_{-1}, b_1, b_2, b_3, \dots, b_n are all possibly different numbers, maybe even fractions. We write this base as (bn,,b3,b2,b1;b1,b2,b3,)(b_n, \dots, b_3, b_2, b_1 ; b_{-1}, b_{-2}, b_{-3}, \dots), and we're going to omit the integer part when it is in decimal

So we can use the base b=(;2,3,4,)\boldsymbol{b} = (; 2, 3, 4, \dots), that is, the radices are all the natural numbers greater than 11, to write (2) as (a0;a1,a2,a3)b(a_0 ; a_1, a_2, a_3\cdots)_{\boldsymbol{b}}. In particular, if we set a0a_0 to 22 and a1,a2,a3,a_{-1}, a_{-2}, a_{-3}, \dots to 11 we can write Euler's number in base b\boldsymbol{b} as (2;1,1,1,)b(2 ; 1, 1, 1, \dots)_{\boldsymbol{b}}. We have created a numeral system where an irrational number can be periodic! We could even write Euler's number as 2.12.\overline{1} if the context is clear.

George Cantor was the first to formalize and generalize mixed radix numeral systems as we just defined, publishing his work in Über einfache Zahlensysteme by the Zeitschrift für Math journal. Remember that these numeral systems are nothing but a way to write a number, and as we saw earlier numbers don't even need to have a unique representation, so this is a perfectly valid way of representing a number.

The same way the representation of a number in some fixed natural radix is regular when all the digits are smaller than the base, in mixed-radix a representation is regular when each did_i is smaller than the numerator of bib_i. So if we now look at (1) we can see that multiplication by an integer in mixed-radix works the same way as in fixed-base: we perform the multiplication in the right-most digit did_i modulo the numerator of bib_i and carry the quotient of di/bid_i / b_i, add the quotient to the next digit and repeat for the next digits.

For example, in base 10 to do 0.8720.87 * 2 we multiply 724mod107 * 2 \equiv 4 \bmod 10, so the first digit is 44, and carry the quotient of 72/107 * 2 / 10, which is 11, and we keep doing this until we get the integer part 11 and the new fractional part 7474. So the manipulations we did in (1) are equivalent to multiplying in base b\boldsymbol{b}! This becomes even clearer when we write 0.870.87 in base 10 as

1+110(8+110(7)).1 + \frac{1}{10}\left(8 + \frac{1}{10}(7)\right).

I'm not going to develop mixed-radix systems any further because we already have all we need to continue.

The Algorithm for ee

As we disucussed, the only problem with our main idea is that the rest of the recursive sum might not actually be the fractional part of the number in question, it might be the case that the sum after a0a_0 in the first expression of (2) is greater than 11. What this means in terms of base b\boldsymbol{b} is that (0;a1,a2,)(0;a_1, a_2, \dots) might not be less than 11 in decimal even though it has integer part 00 in b\boldsymbol{b}.

So we want to know when (0;a1,a2,)1(0; a_1, a_2, \dots) \geq 1. This is a special case of the following lemma.

Lemma 1. If i1i \geq 1 then (0;0,0,,0,ai,ai+1,)b1i(0; 0, 0, \dots, 0, a_i, a_{i + 1}, \dots)_{\boldsymbol{b}} \leq \frac{1}{i}

Proof. This is equivalent to showing that

k=iai(k+1)!1i,\sum_{k = i}^\infty \frac{a_i}{(k + 1)!} \leq \frac{1}{i},

so we let ai,ai+1,a_i, a_{i + 1}, \dots to be their maximum values and we get

k=ik(k+1)!=k=1i+k1(i+k)!=k=1[1(i+k1)!1(i+k)!]=[1i!1(i+1)!]+[1(i+1)!1(i+2)!]+[1(i+2)!1(i+3)!]+\begin{equation} \begin{split} \sum_{k = i}^\infty \frac{k}{(k + 1)!} &= \sum_{k = 1}^\infty \frac{i + k - 1}{(i + k)!} \\ &= \sum_{k = 1}^\infty \left[\frac{1}{(i + k - 1)!} - \frac{1}{(i + k)!}\right] \\ &= \left[\frac{1}{i!} - \frac{1}{(i + 1)!}\right] + \left[\frac{1}{(i + 1)!} - \frac{1}{(i + 2)!}\right] + \left[\frac{1}{(i + 2)!} - \frac{1}{(i + 3)!}\right] + \cdots \end{split} \end{equation}

Since

limkk+1(k+2)!(k+1)!k=limk1k+2+limk1k(k+2)=0\lim_{k \to \infty} \frac{k + 1}{(k + 2)!}\frac{(k + 1)!}{k} = \lim_{k \to \infty} \frac{1}{k + 2} + \lim_{k \to \infty} \frac{1}{k(k + 2)} = 0

the series is absolutely convergent by the ratio test and we are allowed to rearrange it:

1i!+[1(i+1)!1(i+1)!]+[1(i+2)!1(i+2)!]+[1(i+3)!1(i+3)!]+=1i!.\frac{1}{i!} + \left[\frac{1}{(i + 1)!} - \frac{1}{(i + 1)!}\right] + \left[\frac{1}{(i + 2)!} - \frac{1}{(i + 2)!}\right] + \left[\frac{1}{(i + 3)!} - \frac{1}{(i + 3)!}\right] + \cdots = \frac{1}{i!}.

The fact that 1/i!1/i1/i! \leq 1/i completes the proof.

Corollary 1.1. (0;a1a2a3)b=1(0;a_1a_2a_3\dots)_{\boldsymbol{b}} = 1 if and only if ai=bi1a_i = b_i - 1 for all ii, and in this case the integer part of (a0;a1a2a3)b(a_0;a_1a_2a_3\dots)_{\boldsymbol{b}} is a0+1a_0 + 1, otherwise the integer part is a0a_0. The fractional part is never greater than 11.

The above corollary implies that if we choose some amount of precision to compute ee like we did in the introduction section, which is equivalent to setting (ai,ai+1,)(a_i, a_{i + 1}, \dots) to 00 for some i1i \geq 1, and apply the procedure we will never get an integer greater than 99. The only question left is how many digits in b\boldsymbol{b} we actually need. It turns out that we need nn digits is enough, and the proof of this fact is in the proof of the correctness of the following algorithm.

Algorithm A. (Generate the digits of Euler's number in base 10). Given the number of desired digits N\texttt{N} this algorithm outputs N\texttt{N} digits of ee.

Theorem 1. With input nn Algorithm A produces nn digits of ee in Θ(n2)\Theta(n^2) time and Θ(n)\Theta(n) space.

Proof. The algorithm maintains an array of the digits of the fractional part in base b\boldsymbol{b} and does exactly what we did in (2). Lemma 1 shows that this q\texttt{q} in Step 4 will never be greater than 99. So all we have to do now is show that n+3n + 3 digits in b\boldsymbol{b} is enough precision to get nn digits in base 10.

First we will prove that for large enough nn, nn digits of precision is enough. So we need to show that een<1/10ne - e_n < 1/10^n where en=(2;1,1,1,,1)e_n = (2;1, 1, 1, \dots, 1):

een=k=01k!k=0n1k!=1(n+1)!+1(n+2)!+1(n+3)!+<1(n+1)![1+1n+1+1(n+1)2+]=1n!n<1n!\begin{equation} \begin{split} e - e_n &= \sum_{k = 0}^\infty \frac{1}{k!} - \sum_{k = 0}^n \frac{1}{k!} \\ &= \frac{1}{(n + 1)!} + \frac{1}{(n + 2)!} + \frac{1}{(n + 3)!} + \cdots \\ &< \frac{1}{(n + 1)!}\left[1 + \frac{1}{n + 1} + \frac{1}{(n + 1)^2} + \cdots\right] \\ &= \frac{1}{n!n} \\ &< \frac{1}{n!} \end{split} \end{equation}

Stirling's approximation says that

n!<2πn(ne)ne112n,n! < \sqrt{2\pi n}\left(\frac{n}{e}\right)^n e^\frac{1}{12n},

so

1n!<12πn(ee12n)<(en)n.\frac{1}{n!} < \frac{1}{\sqrt{2\pi n}}\left(\frac{e}{e^{12}n}\right) < \left(\frac{e}{n}\right)^n.

By taking the natural logarithm of

(en)n<(110)n\left(\frac{e}{n}\right)^n < \left(\frac{1}{10}\right)^n

we get

1+log10<logn1 + \log{10} < \log{n}

and taking the exponential we get

10e<n.10e < n.

So een<1/10ne - e_n < 1/10^n for every n10e=28n \geq \lceil 10e \rceil = 28. This means that nn digits in b\boldsymbol{b} is enough for nn digits in decimal when n28n \geq 28, and we can manually verify that n+3n + 3 is enough for n<28n < 28. We have to keep in mind that we are counting the integer part, which is already in decimal so we just print it directly in the algorithm. This is why we use an array of length n+2n + 2 to store the digits in base b\boldsymbol{b}.

The fact that the algorithm uses Θ(n)\Theta(n) space is trivial given that we always use an array of length n+2n + 2. Step 2 takes Θ(n)\Theta(n) time and steps from Step 5 to Step 16 take Θ(n2)\Theta(n^2) time so the total running time is Θ(n2)\Theta(n^2).

Here is an implementation of this algorithm in C and Haskell:

#include <stdio.h>
#include <stdlib.h>

void generate_digits_of_e(int n)
{
        int q = 2;
        int len = n + 2;
        int *a = malloc(len * sizeof(int));
        if (!a) {
                fprintf(stderr, "Out of memory.");
                exit(1);
        }
        for (int i = 0; i < len; ++i)
                a[i] = 10;
        printf("%d.", q);
        for (int i = 0; i < n - 1; ++i) {
                for (int j = len - 1; j >= 0; --j) {
                        const int d = a[j];
                        a[j] = d % (j + 2);
                        q = d / (j + 2);
                        a[j - 1] += q;
                }
                printf("%d", q);
                fflush(stdout);
                for (int j = 0; j < len; ++j)
                        a[j] *= 10;
        }
        free(a);
}
digits n = 2 : digits' (n - 1) (replicate (n + 2) 1)
digits' n a@(h:t) = let (qs, rs) = unzip $ scanl f (f (0, 0) (h * 10, initB)) t'
                    in last qs : if n == 1 then [] else digits' (n - 1) rs
  where initB = length a + 1
        t' = zip (map (*10) t) [initB - 1, initB - 2..]
        f (q, _) (n, b) = divMod (n + q) b

This algorithm was first published by A. H. J. Sale in his 1967 paper “The Calculation of ee to Many Significant Digits”.

The Algorithm for π\pi

In 1995 Stanley Rabinowitz and Stan Wagon published a similar algorithm for π\pi. We defined a base b=(2,3,4,)\boldsymbol{b} = (2, 3, 4, \dots) for representing ee and constructed the algorithm for ee by converting this base to decimal, likewise we will use the base c=(3,5/2,7/3,)\boldsymbol{c} = (3, 5/2, 7/3, \dots) based on (3) to represent π\pi as (2,2,2)c(2, 2, 2\dots)_{\boldsymbol{c}}. Base c\boldsymbol{c} is, unfortunately, not as nice as b\boldsymbol{b}. For example, this base with maximal digits and no integer part (meaning every digit did_i in the fractional part is one less than the denominator of bi1b_i^{-1} ) is the number

13(2+25(4+37(6+49(8+))))=123+12435+1236357+123483579+=2n=1n!n(2n+1)!!.\begin{equation} \begin{split} \frac{1}{3}\left( 2 + \frac{2}{5}\left( 4 + \frac{3}{7}\left( 6 + \frac{4}{9}\left( 8 + \cdots \right)\right)\right)\right) &= \frac{1 \cdot 2}{3} + \frac{1 \cdot 2 \cdot 4}{3 \cdot 5} + \frac{1 \cdot 2 \cdot 3 \cdot 6}{3 \cdot 5 \cdot 7} + \frac{1 \cdot 2 \cdot 3 \cdot 4 \cdot 8}{3 \cdot 5 \cdot 7 \cdot 9} + \cdots \\ &= 2\sum_{n = 1}^\infty \frac{n!n}{(2n + 1)!!}. \end{split} \end{equation}

Where x!!x!! is the double factorial, see this Wikipedia article for what it means (it is not just factorial applied twice). Using the identity

(2n+1)!!=(2n+1)!2nn!(2n + 1)!! = \frac{(2n + 1)!}{2^n n!}

we get

2n=12n(n!)2n(2n+1)!=2n=1n22n(n!)2(2n+1)!12n=2n=1n2n01(1x2)ndx=201[n=1n(1x22)n]dx=4011x2(x2+1)2dx=2.\begin{equation} \begin{split} 2\sum_{n = 1}^\infty \frac{2^n(n!)^2 n}{(2n + 1)!} &= 2 \sum_{n = 1}^\infty n\frac{2^{2n}(n!)^2}{(2n + 1)!} \frac{1}{2^n} \\ &= 2 \sum_{n = 1}^\infty \frac{n}{2^n} \int_{0}^1 (1 - x^2)^n \mathop{\mathrm{d}x} \\ &= 2 \int_{0}^1 \left[\sum_{n = 1}^\infty n\left(\frac{1 - x^2}{2}\right)^n\right] \mathop{\mathrm{d}x} \\ &= 4 \int_{0}^1 \frac{1 - x^2}{(x^2 + 1)^2} \mathop{\mathrm{d}x} \\ &= 2. \end{split} \end{equation}

Here I used the fact that

01(1x2)ndx=22n(n!)2(2n+1)!,\int_{0}^1 (1 - x^2)^n \mathop{\mathrm{d}x} = \frac{2^{2n}(n!)^2}{(2n + 1)!},

which can be proven using integration by parts, and

n=1nxn=x(x1)2.\sum_{n = 1}^\infty nx^n = \frac{x}{(x - 1)^2}.

This shows that numbers of the form (0;a1,a2,a3,)c(0 ; a_1, a_2, a_3, \dots)_{\boldsymbol{c}} are in the range [0,2][0, 2] and, in contrast with base b\boldsymbol{b}, the integer part of (a0;a1,a2,a3,)(a_0 ; a_1, a_2, a_3, \dots) may be a0+1a_0 + 1 with limited precision and we may get an integer in the range [10,19][10, 19] after the multiply-reduce-carry stage of the algorithm.

This is not hard to fix. The algorithm is almost the same, but instead of printing the digit right away we hold it for as long as the next digits are 9's. If we then get an integer greater than 9 we add 1 to the pre-digit we first got and print it, then we print 0's instead of 9's, otherwise we print the pre-digit, all the 9's and set the new pre-digit to the integer modulo 1010. There is nothing complicated going on here, just multiplication with carry. Of course, we only print as many digits as needed, so we may not print all the 9's or all the 0's.

So this algorithm has a very serious flaw compared to the algorithm for Euler's number: at the beginning we need to specify a number of digits to be printed, but we may reach a sequence of 9's that goes beyond this limit, in which case the algorithm would terminate without fixing the pre-digit, possibly printing one minus the correct digit, and a bunch of 9's. We can't fix this by simply allocating more memory for the array and continuing as if we started with more precision since this would mess up the array's state. It is also not possible (or is it?) to predict in advance where and how long the sequences of 9's are, coming up with such a method could even lead to a proof that π\pi is or is not normal, an open problem in mathematics. So if you get a sequence of 9's, you need to call the algorithm again with more digits to be sure the digits are correct.

That being said, the authors of the original paper say that we need 10n/3\lfloor 10n/3 \rfloor base c\boldsymbol{c} digits but, as you can check with n=1n = 1, this is wrong and we actually need 10n/3+1\lfloor 10n/3 \rfloor + 1 digits. Here is the code in C:

#include <stdio.h>
#include <stdlib.h>

void generate_digits_of_pi(int n)
{
        const int len = (10 * n) / 3 + 1;
        int *const a = malloc(len * sizeof(len));
        if (!a) {
                fprintf(stderr, "Out of memory.");
                exit(1);
        }
        for (int i = 0; i < len; ++i)
                a[i] = 2;
  
        int nines = 0;
        int predigit = -1;
        while (n >= 0) {
                for (int j = 0; j < len; ++j)
                        a[j] *= 10;
                int q;
                for (int j = len - 1; j >= 1; --j) {
                        const int d = a[j];
                        a[j] = d % (2 * j + 1);
                        q = d / (2 * j + 1);
                        a[j - 1] += q * j;
                }
                // Remember that the integer part of base c uses base 10.
                const int d = a[0];
                a[0] = d % 10;
                q = d / 10;
                if (q == 9) {
                        ++nines;
                } else {
                        // This prints predigit + 1 if the quotient is greater
                        // than 9 and predigit otherwise.
                        if (predigit >= 0)
                                printf("%d", predigit + q / 10);
                        if (n < nines)
                                nines = n;
                        // Decrease n by the number of digits we are about to
                        // print plus the digit we printed.
                        n -= nines + 1;
                        while (--nines >= 0)
                                printf("%d", q == 10 ? 0 : 9);
                        nines = 0;
                        predigit = q == 10 ? 0 : q;
                }
                fflush(stdout);
        }
       free(a);
}

I'm not going to go over the correctness of this algorithm since the idea is basically the same as the algorithm for ee, if you are interested check the paper by Stanley Rabinowitz and Stan Wagon. Jeremy Gibbons published an algorithm that doesn't have the problems I mentioned, in the paper “Unbounded Spigot Algorithms for the Digits of Pi”. The purpose of the last sections was to present the idea of spigot algorithms and how they can be constructed, if you really are interested in this kind of thing I recommend reading this paper, as I'm about to move on to something a lot more interesting.

Digit Extraction Algorithms

In 1995 Simon Plouffe discovered the remarkable formula

π=k=0116k(48k+128k+418k+518k+6).\pi = \sum_{k = 0}^\infty \frac{1}{16^k} \left( \frac{4}{8k + 1} - \frac{2}{8k + 4} - \frac{1}{8k + 5} - \frac{1}{8k + 6} \right).

This is the BBP formula, named after David Bailey, Peter Borwein and Plouffe. This formula is special because we can use it to construct a spigot algorithm that is a lot more interesting than the previous algorithm: not only can we generate π\pi digit by digit, but we can also calculate the nth hexadecimal digit of π\pi without calculating the preceding digits!

To see how this is possible first let

Si=4k=016k8k+iS_i = 4 \sum_{k = 0}^\infty \frac{16^{-k}}{8k + i}

and notice that the digit of π\pi in position (n2)(n - 2) from 1 (counting the integer part) is the first digit in the fractional part of

{16nπ}={416nS1216nS416nS516nS6}.\{16^n \pi\} = \{4 \cdot 16^n S_1 - 2 \cdot 16^n S_4 - 16^n S_5 - 16^n S_6\}.

where {x}=xx\{x\} = x - \lfloor x \rfloor means the fractional part of {x}\{x\}. We are just shifting digits and removing the integer part. From this definition of fractional part we can see that if nn is an integer then

{x+n}=a+na+n=a+nan=aa={a}\{x + n\} = a + n - \lfloor a + n \rfloor = a + n - \lfloor a \rfloor - n = a - \lfloor a \rfloor = \{a\}

which gives us

{{a}+{b}}={aa+bb}=(a+b)(a+b)(a+b)(a+b)={(a+b)(a+b)(a+b)+(a+b)}={(a+b)a+b}={a+b}.\begin{align} \{\{a\} + \{b\}\} &= \{a - \lfloor a \rfloor + b - \lfloor b \rfloor\} \\ &= (a + b) - (\lfloor a \rfloor + \lfloor b \rfloor) - \lfloor (a + b) - (\lfloor a \rfloor + \lfloor b \rfloor) \rfloor \\ &= \{(a + b) - \lfloor (a + b) - (\lfloor a \rfloor + \lfloor b \rfloor) + (\lfloor a \rfloor + \lfloor b \rfloor) \rfloor\} \\ &= \{(a + b) - \lfloor a + b \rfloor\} \\ &= \{a + b\}. \end{align}

We can also show that {{a}{b}}={ab}\{\{a\} - \{b\}\} = \{a - b\} the same way. Now we can write

{16nπ}={{416nS1}{216nS4}{16nS5}{16nS6}}.\{16^n \pi\} = \{\{4 \cdot 16^n S_1\} - \{2 \cdot 16^n S_4\} - \{16^n S_5\} - \{16^n S_6\}\}.

Let's isolate {16nSi}\{16^n S_i\}:

{16nSj}={{k=0n16nk8k+i}+k=n+116nk8k+i}.\left\{16^n S_j\right\} = \left\{ \left\{\sum_{k = 0}^n \frac{16^{n - k}}{8k + i}\right\} + \sum_{k = n + 1}^\infty \frac{16^{n - k}}{8k + i} \right\}.

The second sum didn't have an integer part in the first place so we don't need to take the fractional part. To see this, just consider the geometric series

n=1116n<1.\sum_{n = 1}^\infty \frac{1}{16^n} < 1.

So only the first sum has terms with integer part. Since we are taking the fractional part we can remove the integer part of every term by reducing the numerator modulo the denominator (the remainder of a/ba/b divided by bb is equal to the fractional part of a/ba/b ). So we now have

Σi={{k=0n16nkmod(8k+i)8k+i}+k=n+116nk8k+i}.\Sigma_i = \left\{\left\{ \sum_{k = 0}^n \frac{16^{n - k} \bmod (8k + i)}{8k + i}\right\} + \sum_{k = n + 1}^\infty \frac{16^{n - k}}{8k + i}\right\}.

Putting everything together:

{16nπ}={4Σ12Σ4Σ5Σ6}.\{16^n\pi\} = \{4\Sigma_1 - 2\Sigma_4 - \Sigma_5 - \Sigma_6\}.

Of course, the digit we want is 16{16nπ}\lfloor 16 \{16^n\pi\} \rfloor, and now we have a great way to calculate this. The right sum of Σi\Sigma_i is very small and for large nn it quickly gets smaller than our floating-point precision of choice can represent. We can also use binary modulo exponentiation to compute 16nkmod(8k+i)16^{n - k} \bmod (8k + i) efficiently, this is the full source code:

#include <math.h>
#include <stdint.h>
#include <stdio.h>
    
/*
 * Returns 16 raised to n, modulo m.
 */
static double expm2(long n, double m)
{
        if (m == 1)
                return 0;
        double result = 1.;
        long double base = fmod(16, m);
        while (n > 0) {
                if (n % 2 == 1)
                        result = fmod(result * base, m);
                n /= 2;
                base = fmod(base * base, m);
        }
        return result;
}
    
/*
 * We need the modulo to be always non-zero since although the digits in the
 * fractional part are all correct the ones in the integer part are not, which
 * means we might end up with a negative number in the last stage of the
 * algorithm where we use modulo 1 to take the fractional part.
 */
static double mod(double x, long m)
{
        x = fmod(x, (double)m);
        return x < 0 ? x + m : x;
}
   
static double sigma(long i, long n)
{
        double s = 0;
    
#pragma omp parallel for reduction(+:s)
        for (long k = 0; k <= n; ++k) {
                const double m = 8 * k + i;
                const double a = expm2(n - k, m) / m;
                s += mod(a, 1);
        }
    
        for (long k = n + 1; k < 20; ++k)
            s += pow(16, n - k) / (8 * k + i);
   
        return mod(s, 1);
}
    
int get_digit(long n) {
        n -= 2;
        double acc = 0;
        acc += 4 * sigma(1, n);
        acc -= 2 * sigma(4, n);
        acc -= sigma(5, n);
        acc -= sigma(6, n);
        return (int)floor(16 * mod(acc, 1));
}

Since this algorithm is embarrassingly parallel I took the liberty of adding an OpenMP pragma to speed things up. The amount of precision required depends on how far the digit is, at some point using 64-bit floating point numbers will not be enough and you would have to use a library like MPFR with some numerical analysis to estimate how much precision you need, but a 64-bit float was enough for me to calculate the 10,000,000th digit (it is AA!) in 2 seconds. Also, by computing the digit we want we inevitably compute the next few digits so with enough floating-point precision and terms in the sums we can get not only the nth digit but also kk digits from that position by multiplying by 16k16^k instead of just 1616. It is important to understand that the reason why this algorithm works is because of the division by 1/16k1/16^k in the BBP formula, which allows us to multiply by 16n16^n and split each sum into two, this is why this formula is special.

In 1997 Fabrice Bellard discovered the formula

π=126n=0(1)n210n(254n+114n+32810n+12610n+32210n+52210n+7110n+9)\pi = \frac{1}{2^6} \sum_{n = 0}^\infty \frac{(-1)^n}{2^{10n}}\left( -\frac{2^5}{4n + 1} -\frac{1}{4n + 3} -\frac{2^8}{10n + 1} -\frac{2^6}{10n + 3} -\frac{2^2}{10n + 5} -\frac{2^2}{10n + 7} -\frac{1}{10n + 9} \right)

which allows to calculate the hexadecimal or binary digits of π\pi 43% faster than the BBP formula. Using 20 computers in parallel Bellard calculated 152 binary digits of π\pi starting from the trillionth position. Colin Percival calculated the quadrillionth binary digit 00 in his PiHex project using a distributed network of 1,734 computers in 56 different countries.

There are many known BBP-type formulas for other constants:

log2=k=112kklog109=k=110kkarctan1b=k=1sinkπ2bkk\begin{alignat}{2} &\log{2} = &\sum_{k = 1}^\infty \frac{1}{2^k k}\\ &\log{\frac{10}{9}} = &\sum_{k = 1}^\infty \frac{10^k}{k}\\ &\arctan{\frac{1}{b}} = &\sum_{k = 1}^\infty \frac{\sin{\frac{k\pi}{2}}}{b^k k}\\ \end{alignat}

In the arctan\arctan one bb is an integer. In general, this kind of formula has the form

α=k=0p(k)bkq(k)\alpha = \sum_{k = 0}^\infty \frac{p(k)}{b^k q(k)}

where pp and qq are polynomials with integer coefficients and bb is an integer greater than one (this is also the base for which we can construct a digit extraction algorithm).