I am attempting to re-implement a postponed sieve algorithm for generating prime numbers in Rust. I am able to make a solution that works, but I have to use a couple of .clone()
calls which I believe are killing my performance (the Rust solution ends up ~8x slower than the Python solution).
I would love some advice on how I can avoid the .clone()
calls while avoiding errors from the borrow checker.
use std::collections::HashMap;
#[derive(Debug, Clone)]
struct Primes {
i: usize,
curr_candidate: u64,
next_relevant_prime: u64,
next_relevant_prime_squared: u64,
sieve: HashMap<u64, u64>,
initial_primes: Vec<u64>,
internal_primes: Box<Option<Primes>>,
}
impl Primes {
fn new() -> Primes {
Primes {
i: 0,
curr_candidate: 7,
next_relevant_prime: 0,
next_relevant_prime_squared: 0,
sieve: HashMap::new(),
initial_primes: vec![2, 3, 5, 7],
internal_primes: Box::new(None),
}
}
}
impl Iterator for Primes {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
let len = self.initial_primes.len();
let mut internal_primes;
if self.i < len {
self.i += 1;
return Some(self.initial_primes[self.i - 1]);
} else if self.i == len {
self.i += 1;
internal_primes = Primes::new();
self.internal_primes = Box::new(Some(internal_primes.clone()));
internal_primes.next(); // skip 2
self.next_relevant_prime = internal_primes.next().unwrap();
self.next_relevant_prime_squared = self.next_relevant_prime.pow(2);
} else {
internal_primes = self.internal_primes.clone().unwrap();
}
let mut i = self.curr_candidate;
loop {
i += 2;
let step;
if self.sieve.contains_key(&i) {
// composite
step = self.sieve.remove(&i).unwrap();
} else if i < self.next_relevant_prime_squared {
// prime
// save state for next round
self.curr_candidate = i;
self.internal_primes = Box::new(Some(internal_primes));
return Some(i);
} else {
// i == next_relevant_prime_squared
step = 2 * self.next_relevant_prime;
self.next_relevant_prime = internal_primes.next().unwrap();
self.next_relevant_prime_squared = self.next_relevant_prime.pow(2);
}
let mut j = i;
j += step;
while self.sieve.contains_key(&j) {
j += step;
}
self.sieve.insert(j, step);
}
}
}
fn main() {
let mut primes = Primes::new();
for _i in 0..99_999 {
primes.next();
}
println!("The 100,000th prime is {}", primes.next().unwrap())
}