Intuition, Vocabulary and Foundations
A sieve treats a range of integers like a checklist. Begin with every integer from $2$ through $n$ as a possible prime, then cross out each number once a known prime proves it composite. For example, sieving through $30$ leaves
$$ 2,3,5,7,11,13,17,19,23,29. $$
This resembles eliminating impossible candidates from a search: each discovered prime supplies a rule that rejects all of its larger multiples. A prime has exactly two positive divisors, while a composite integer can be expressed as a product of smaller positive integers.
In the Sieve of Eratosthenes, a composite $m$ is marked when a prime $p$ divides it. Marking may begin at $p^2$, because every smaller multiple $kp$ with $2\le k\lt p$ already has a prime factor smaller than $p$.
The smallest prime factor, written $\operatorname{spf}(m)$, is the least prime dividing $m$. Repeatedly dividing by this value recovers the full factorization. For example,
$$ 84\longrightarrow42\longrightarrow21\longrightarrow7\longrightarrow1 $$
extracts $2,2,3,7$, so $84=2^2\cdot3\cdot7$.
A segmented sieve marks only an interval $[L,R]$. It first computes all primes through $\lfloor\sqrt R\rfloor$, because every composite not exceeding $R$ has a prime factor no greater than its square root. Those base primes can then process one memory-sized block at a time.
Bulk precomputation can also produce arithmetic-function tables. Euler's totient $\varphi(n)$ counts the integers in $\{1,\ldots,n\}$ coprime to $n$. The Möbius function $\mu(n)$ is $0$ when a squared prime divides $n$; otherwise it is $(-1)^k$ when $n$ is a product of $k$ distinct primes.
The central invariant is that every processed composite has been marked using a prime divisor, while an unmarked candidate is prime when selected. Starting at $p^2$ is valid precisely because all smaller multiples of $p$ already have a smaller prime factor.
| Method | Stored information | Concrete example | Assumption | Best question |
|---|---|---|---|---|
| Eratosthenes | Prime status through $n$ | $25$ is marked by $5$ | A dense prefix fits in memory | Which values through $n$ are prime? |
| Odd-only sieve | Status of odd candidates | Slot $k$ represents $2k+1$ | Handle $2$ separately | How can dense prime generation use fewer flags? |
| SPF table | $\operatorname{spf}(m)$ for each $m$ | $\operatorname{spf}(84)=2$ | Queries stay within the table | How can many values be factored quickly? |
| Segmented sieve | Status within one block $[L,R]$ | Find primes in $[100,130]$ | Base primes through $\lfloor\sqrt R\rfloor$ are known | Which primes occur in a distant interval? |
| Linear sieve | Prime list and least factor | $12$ is generated from $6\cdot2$ | A dense prefix is required | How can each composite be generated once? |
| Function tables | Values such as $\varphi(n)$ and $\mu(n)$ | $\varphi(10)=4$, $\mu(12)=0$ | Prime-extension recurrences are known | How can bulk arithmetic queries be answered? |
Step-by-Step Derivations and Algorithms
For the ordinary sieve, allocate flags for $0$ through $n$, mark $0$ and $1$ non-prime, and inspect candidates through $\lfloor\sqrt n\rfloor$. Whenever $p$ remains unmarked, mark
$$ p^2,\ p^2+p,\ p^2+2p,\ldots $$
as composite. If some composite $m\le n$ remained unmarked, its least prime factor $p$ would satisfy $p\le\sqrt m\le\sqrt n$, so the iteration for $p$ would mark $m$. This contradiction proves completeness. The total marking work is
$$ O\!\left(n\sum_{p\le n}\frac1p\right)=O(n\log\log n), $$
with $O(n)$ storage. An odd-only representation removes even candidates after handling $2$, improving constants without changing the asymptotic bounds.
For a block $[L,R]$, each base prime $p\le\sqrt R$ begins at
$$ \max\!\left(p^2,\left\lceil\frac Lp\right\rceil p\right). $$
The ceiling term selects the first multiple inside the block, while $p^2$ prevents the prime $p$ itself from being marked. A block of width $B$ needs $O(B)$ working storage in addition to the base-prime table.
The linear sieve maintains a prime list and an SPF table. For each $i$, it generates $ip$ in increasing prime order and stops after processing the first prime $p$ dividing $i$. Thus every composite is assigned to its least prime factor exactly once. SPF factorization then repeatedly replaces $x$ by $x/\operatorname{spf}(x)$, requiring at most $\lfloor\log_2x\rfloor$ divisions.
flowchart TD
A["Choose range and required outputs"] --> B{"Dense prefix fits in memory?"}
B -->|Yes| C{"Need factors or functions?"}
B -->|No| D["Generate base primes through sqrt R"]
C -->|No| E["Run Eratosthenes or odd-only sieve"]
C -->|Yes| F["Run linear sieve with SPF, phi, and mu"]
D --> G["Mark one segment at a time"]
E --> H["Answer prime queries"]
F --> I["Answer factor and function queries"]
G --> H
Correctness comes from the least-prime-factor witness: every composite has a prime divisor no greater than its square root. Eratosthenes uses $O(n\log\log n)$ time, the linear sieve uses $O(n)$ time, segmented sieving uses $O(\sqrt R+B)$ storage for block width $B$, and an SPF factorization takes $O(\log x)$ divisions in the worst case.
Implementation, Complexity and Engineering
A robust implementation rejects invalid bounds, represents $0$ and $1$ explicitly as non-prime, and uses integer square roots. In a fixed-width language, the loop condition $p\le n/p$ avoids overflowing while evaluating $p^2\le n$. Packed bitsets minimize memory, whereas byte arrays often offer simpler indexing and good cache behavior.
Segment width is an engineering parameter. Blocks that are too small repeat setup work; blocks that are too large may leave cache. Benchmark representative ranges and query batches instead of selecting a size from asymptotic notation alone.
| Implementation | Complexity | Main constraint | Common failure | Mitigation |
|---|---|---|---|---|
| Boolean Eratosthenes | $O(n\log\log n)$ time, $O(n)$ flags | Language booleans may consume a byte or more | Memory exhaustion | Use bytes, packed bits, or odd-only indexing |
| Odd-only sieve | Same time, about half the candidate flags | Slot indices differ from represented values | Off-by-one conversion | Centralize the slot mapping and test small limits |
| Linear sieve with SPF | $O(n)$ time, $O(n)$ integer storage | Several arrays dominate memory | Computing unused tables | Materialize only the arrays required by the workload |
| Segmented sieve | Block marking plus base-prime generation | Block width affects cache and setup cost | Wrong first multiple | Use $\max(p^2,\lceil L/p\rceil p)$ and test intervals containing $p$ |
| Fixed-width implementation | Same asymptotic bounds | Products and allocation sizes can overflow | Unsafe loop or allocation | Use integer square roots and checked arithmetic |
| SPF query service | $O(\log x)$ worst-case query steps | Every query must satisfy $1\le x\le n$ | Out-of-range access | Validate bounds and store the table limit |
Applications, Case Studies and Exercises
Dense sieves are ideal when many queries share a moderate upper bound. One preprocessing pass can support primality checks, factorizations, divisor statistics, totients, and Möbius values. Segmented sieves target a different workload: the right endpoint may be enormous, but only a manageable interval needs to reside in memory.
A strong test oracle compares optimized output with trial division on small random ranges. Useful invariants include a strictly increasing prime list, $\operatorname{spf}(x)\mid x$, primality of every nonzero SPF value, and reconstruction of each input from its factorization.
Apply Sieves & Bulk Precomputation
Case study 1 — batch factorization. Build tables through $100$, then answer queries for $84$, $90$, $97$, and $100$.
- Generate the prime list and SPF table with
linear_sieve(100). - Follow SPF links until each value reaches $1$.
- Verify $84=2^2\cdot3\cdot7$, $90=2\cdot3^2\cdot5$, $97$ is prime, and $100=2^2\cdot5^2$.
- Reconstruct every input from its factor map.
Success criterion: every extracted factor is prime, every reconstructed product equals its input, and every lookup remains within the table.
Case study 2 — distant interval scan. Find the primes in $[100,130]$ without allocating a table for every integer through $130$.
- Generate base primes through $\lfloor\sqrt{130}\rfloor=11$.
- For each $p\in\{2,3,5,7,11\}$, begin at $\max(p^2,\lceil100/p\rceil p)$.
- Verify that the survivors are $101,103,107,109,113,127$.
- Split the interval into smaller blocks and confirm that concatenating their results gives the same list.
Success criterion: the segmented result equals trial division, including intervals whose endpoints are below $2$ or equal to a base prime.
Tiered exercises
- Recall: Explain why neither $0$ nor $1$ is prime.
- Trace: List each value newly marked while processing $p=3$ through $40$.
- Derivation: Prove that every composite $m$ has a prime divisor no greater than $\sqrt m$.
- Implementation: Replace the dense sieve with an odd-only representation and document its index mapping.
- Debugging: Find the error in a segmented sieve that always starts at $\lceil L/p\rceil p$.
- Analysis: Measure the actual memory of a packed sieve and an SPF table through $10^7$.
- Extension: Compute divisor counts from SPF factorizations for every integer through $n$.
- Challenge: Process a range too large for one block and verify its output against the dense method on smaller ranges.
Choose a dense sieve for repeated prefix queries, an SPF or linear-sieve table for bulk factorization and arithmetic functions, and a segmented sieve for distant or memory-constrained ranges. Common mistakes include treating $1$ as prime, marking before $p^2$, overflowing products, and mishandling interval endpoints; these invariants prepare the way for modular arithmetic and fast exponentiation.
Next in the Series
In Modular Arithmetic & Fast Exponentiation, we'll explore Compute safely and efficiently in residue classes..