use std::thread;
use std::sync::mpsc;
use std::error::Error;
extern crate itertools;
use itertools::Itertools;
struct SquareMultiple {
curr: usize,
increment: usize,
}
impl Iterator for SquareMultiple {
type Item = usize;
fn next(&mut self) -> Option<usize> {
let val = self.curr;
self.curr += self.increment;
Some(val)
}
}
impl SquareMultiple {
fn new(term: usize) -> Self {
SquareMultiple { curr: term * term, increment: term }
}
}
pub fn eratosthenes_sieve(max_val: usize) -> Vec<usize> {
let mut bool_vec = vec![true; max_val];
let mut top_sieve = max_val as f64;
top_sieve = top_sieve.sqrt().ceil();
for sieve_term in 2..(top_sieve as usize) {
if bool_vec[sieve_term] == true {
for j in SquareMultiple::new(sieve_term)
.take_while(|&term| term < max_val) { bool_vec[j] = false; }
}
}
bool_vec[2..]
.iter().enumerate() .filter(|&(_, val)| *val) .map(|(ind, _)| ind + 2) .collect()
}
pub fn segmented_sieve(max_val: usize, segment_size: usize) -> Vec<usize> {
if max_val <= 2usize.pow(16) {
return eratosthenes_sieve(max_val);
}
let alpha = (max_val as f64).sqrt() as usize;
let segment_size = if segment_size > alpha {
println!("Segment size is larger than √{}. Reducing to {} to keep resource use down.",
max_val, segment_size);
alpha
} else {
segment_size
};
let small_primes = eratosthenes_sieve(alpha);
let mut big_primes = small_primes.clone();
for this_segment in (segment_size..max_val).collect::<Vec<_>>()
.chunks(segment_size) {
big_primes.extend(sieve_segment(&small_primes, this_segment));
}
big_primes
}
pub fn segmented_sieve_parallel(max_val: usize, mut segment_size: usize) -> Vec<usize> {
if max_val <= ((2 as i64).pow(16) as usize) {
return eratosthenes_sieve(max_val);
}
if segment_size > ((max_val as f64).sqrt() as usize) {
segment_size = (max_val as f64).sqrt() as usize;
println!("Segment size is larger than √{}. Reducing to {} to keep resource use down.",
max_val, segment_size);
}
let small_primes = eratosthenes_sieve((max_val as f64).sqrt() as usize);
let mut big_primes = small_primes.clone();
let (tx, rx): (mpsc::Sender<Vec<usize>>, mpsc::Receiver<Vec<usize>>) = mpsc::channel();
let extended_vec: Vec<_> = (segment_size..max_val).collect();
let extended_segments = extended_vec.chunks(segment_size);
for this_segment in extended_segments.clone() {
let this_segment = this_segment.to_vec();
let small_primes = small_primes.clone();
let tx = tx.clone();
thread::spawn(move || {
let sieved_segment = sieve_segment(&small_primes, &this_segment);
tx.send(sieved_segment).unwrap_or_else(|why| {
println!("Segment sieve failed: {}", why.description());
});
});
}
for _ in 0..extended_segments.count() {
big_primes.extend(&rx.recv().unwrap());
}
big_primes
}
fn sieve_segment(primes: &Vec<usize>, target_vec: &[usize]) -> Vec<usize> {
let mut sieved_segment = Vec::with_capacity(target_vec.len());
sieved_segment.extend(target_vec);
for &this_prime in primes {
if !sieved_segment.is_empty() {
let first_val = target_vec[0];
let mut starting_offset = first_val % this_prime;
starting_offset = if starting_offset == 0 { this_prime } else { starting_offset };
let first_val = first_val + this_prime - starting_offset;
let last_val: &usize = target_vec.last().unwrap();
let sieve_vec: Vec<_> = (first_val..(*last_val + 1))
.step(this_prime)
.collect();
sieved_segment = sieved_segment
.iter()
.filter(|check_num| !sieve_vec.contains(check_num))
.cloned()
.collect();
}
}
sieved_segment
}