Sieve of Eratosthenes
Tutorial Video
Text description (accessibility)
This video demonstrates the "Sieve of Eratosthenes" functional Rust example. Difficulty level: Intermediate. Key concepts covered: Functional Programming. Generating all prime numbers up to N is a fundamental operation in number theory with applications in cryptography (RSA key generation requires large primes), competitive programming, and mathematical software. Key difference from OCaml: | Aspect | Rust | OCaml |
Tutorial
The Problem
Generating all prime numbers up to N is a fundamental operation in number theory with applications in cryptography (RSA key generation requires large primes), competitive programming, and mathematical software. Trial division for each number takes O(sqrt(n)) per number, giving O(n*sqrt(n)) total. The Sieve of Eratosthenes achieves O(n log log n) by marking multiples of each prime in bulk: once 2's multiples are marked, 3's multiples, 5's multiples, etc. Every composite number gets eliminated exactly once. For N up to 10^7, the sieve runs in milliseconds and uses O(n) memory. Segmented variants extend this to arbitrary ranges without holding all of 0..N in memory.
🎯 Learning Outcomes
Code Example
#![allow(clippy::all)]
//! # Sieve of Eratosthenes
pub fn sieve(n: usize) -> Vec<bool> {
let mut is_prime = vec![true; n + 1];
is_prime[0] = false;
if n >= 1 {
is_prime[1] = false;
}
for i in 2..=((n as f64).sqrt() as usize) {
if is_prime[i] {
for j in (i * i..=n).step_by(i) {
is_prime[j] = false;
}
}
}
is_prime
}
pub fn primes_up_to(n: usize) -> Vec<usize> {
sieve(n)
.iter()
.enumerate()
.filter_map(|(i, &b)| if b { Some(i) } else { None })
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sieve() {
assert_eq!(primes_up_to(20), vec![2, 3, 5, 7, 11, 13, 17, 19]);
}
}Key Differences
| Aspect | Rust | OCaml |
|---|---|---|
| Array init | vec![true; n+1] | Array.make (n+1) true |
| Outer loop | while p * p <= n | for p = 2 to isqrt n |
| Inner loop | while m <= n { m += p } | let m = ref (p*p); while !m <= n |
| Memory (bool) | 1 byte/bool (8x waste) | 1 word/bool (worse) |
| Result type | Vec<bool> (sieve) or Vec<usize> | bool array or int list |
| Segmented variant | Manual chunk iteration | Same approach |
OCaml Approach
OCaml implements the sieve with Array.make (n+1) true and two nested loops using for and while. The functional equivalent uses Array.iteri for the outer loop, though mutable array mutation is idiomatic here. OCaml's Array.to_seqi |> Seq.filter_map (fun (i, b) -> if b then Some i else None) generates prime sequences lazily. The Bigarray module provides compact bit arrays for memory efficiency. OCaml's Printf.printf easily prints prime counts for verification.
Full Source
#![allow(clippy::all)]
//! # Sieve of Eratosthenes
pub fn sieve(n: usize) -> Vec<bool> {
let mut is_prime = vec![true; n + 1];
is_prime[0] = false;
if n >= 1 {
is_prime[1] = false;
}
for i in 2..=((n as f64).sqrt() as usize) {
if is_prime[i] {
for j in (i * i..=n).step_by(i) {
is_prime[j] = false;
}
}
}
is_prime
}
pub fn primes_up_to(n: usize) -> Vec<usize> {
sieve(n)
.iter()
.enumerate()
.filter_map(|(i, &b)| if b { Some(i) } else { None })
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sieve() {
assert_eq!(primes_up_to(20), vec![2, 3, 5, 7, 11, 13, 17, 19]);
}
}#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sieve() {
assert_eq!(primes_up_to(20), vec![2, 3, 5, 7, 11, 13, 17, 19]);
}
}
Deep Comparison
OCaml vs Rust: Sieve Of Eratosthenes
Overview
See the example.rs and example.ml files for detailed implementations.
Key Differences
| Aspect | OCaml | Rust |
|---|---|---|
| Type system | Hindley-Milner | Ownership + traits |
| Memory | GC | Zero-cost abstractions |
| Mutability | Explicit ref | mut keyword |
| Error handling | Option/Result | Result<T, E> |
See README.md for detailed comparison.
Exercises
spf[i] = smallest prime dividing i, useful for fast factorization.BitVec-backed sieve and measure memory and speed improvement vs Vec<bool>.