Spigot algorithm
pi calculation
algorithm implementation
mathematical algorithms
computational mathematics

Implementing the Spigot algorithm for `π` pi

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

The spigot algorithm is interesting because it emits digits of π one at a time. Instead of repeatedly refining a floating-point approximation, it keeps an integer state and “drips” out decimal digits in sequence.

That makes it a good teaching algorithm. It is not the fastest way to compute millions of digits, but it is compact, deterministic, and useful for learning how digit-extraction algorithms work.

Why It Is Called a Spigot Algorithm

A spigot algorithm produces output incrementally, like water coming from a tap. After enough internal updates, one more digit becomes safe to print without changing later. That is the key distinction from methods that compute a big approximation and only then format the result.

For π, the classic decimal spigot algorithm uses an integer array and repeated carry propagation. The state array stores partial remainders, and each outer iteration pushes the system one step closer to the next stable digit.

A Runnable Python Implementation

The following implementation generates decimal digits as a string. It uses only integer arithmetic.

python
1def pi_spigot(digits: int) -> str:
2    if digits <= 0:
3        return ""
4
5    boxes = digits * 10 // 3
6    reminders = [2] * boxes
7    held_digits = 0
8    result = []
9    predigit = 0
10
11    for _ in range(digits):
12        carry = 0
13
14        for i in range(boxes - 1, -1, -1):
15            x = reminders[i] * 10 + carry
16            divisor = 2 * i + 1
17            reminders[i] = x % divisor
18            carry = (x // divisor) * i
19
20        q = carry // 10
21
22        if q == 9:
23            held_digits += 1
24        elif q == 10:
25            result.append(str(predigit + 1))
26            result.extend("0" for _ in range(held_digits))
27            predigit = 0
28            held_digits = 0
29        else:
30            result.append(str(predigit))
31            predigit = q
32            if held_digits:
33                result.extend("9" for _ in range(held_digits))
34                held_digits = 0
35
36    result.append(str(predigit))
37    return result[1] + "." + "".join(result[2:])
38
39
40print(pi_spigot(15))

For a short run, this prints 3.14159265358979. The implementation avoids floating-point rounding issues because every step stays in integer space.

How the Carry Logic Works

The hardest part is not the array update itself. It is the logic around predigit, 9, and 10.

Sometimes the next extracted value is definitely safe, so you can append it immediately. Sometimes it is 9, which means the previous digit might still need to be adjusted later. Sometimes it becomes 10, which means a carry ripples backward and turns any held 9 digits into 0 digits.

That is why the code keeps:

  • 'predigit for the most recent tentative digit'
  • 'held_digits for a run of pending 9 values'
  • 'result for finalized digits'

Without that bookkeeping, you will occasionally emit incorrect digits near carry boundaries.

Performance Characteristics

This approach is educational, but it is not the best algorithm for high-performance arbitrary-precision work. Modern π computations often use formulas such as Chudnovsky with fast multiplication libraries.

The spigot method remains useful when you want:

  • a digit-by-digit generator
  • a small integer-only implementation
  • an algorithm that is easy to trace by hand on small examples

Space usage grows with the number of digits requested because the remainder array must be large enough to support the extraction process.

When to Use It

Use the spigot algorithm in classroom material, coding interviews about number generation, or toy projects that print the first few hundred digits. If your real goal is numerical analysis or serious high-precision computation, choose a faster algorithm and a big-number library.

The important lesson is algorithmic shape, not just the constant factor. Spigot-style digit generation shows that there are cases where output can be streamed one symbol at a time while preserving correctness.

Common Pitfalls

  • Using floating-point arithmetic. That defeats the purpose and introduces rounding errors into a digit-extraction algorithm.
  • Emitting 9 digits too early. They may need to change if a later carry produces 10.
  • Forgetting the final pending digit. The last predigit still has to be appended after the loop.
  • Assuming this is the fastest π algorithm available. It is mainly valuable for clarity and incremental output.
  • Choosing an array that is too small. The working state must be sized relative to the number of digits requested.

Summary

  • The spigot algorithm generates digits of π incrementally.
  • A practical implementation uses integer arithmetic and a remainder array.
  • Correct handling of tentative 9 and 10 cases is the core detail.
  • The algorithm is ideal for learning and small demonstrations.
  • For very large computations, faster high-precision methods are usually a better choice.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.