optimize sieve of Eratosthenes

This commit is contained in:
Dr. Matthias Ratajczak
2022-08-16 16:14:08 +02:00
parent b68b9f1200
commit 61817120b1
+37 -9
View File
@@ -33,10 +33,14 @@ where
}
fn from_array(array: Vec<bool>, min_value: &usize, max_value: &usize) -> Self {
let mut vector = Vec::new();
let mut set = HashSet::new();
let number_of_primes = array.iter().filter(|b| **b).count();
let mut vector = Vec::with_capacity(number_of_primes);
let mut set = HashSet::with_capacity(number_of_primes);
for number in *min_value..*max_value {
if array[(number - min_value) as usize] {
let idx = number - min_value;
// SAFETY: see considerations in get_prime_numbers_array
if unsafe { *array.get_unchecked(idx) } {
let prime = FromPrimitive::from_usize(number).unwrap();
vector.push(prime);
set.insert(prime);
@@ -51,18 +55,30 @@ where
let length = *max_value - *min_value;
let mut result = vec![true; length];
let upper_limit = f64::sqrt(*max_value as f64).ceil() as usize;
let upper_limit = Self::calc_upper_limit(max_value);
for i in 2..upper_limit {
for multiple in ((i * i)..*max_value).step_by(i) {
if &multiple < min_value {
continue;
}
result[multiple - min_value] = false;
let skip = Self::find_number_to_skip_until_min_value(min_value, i);
for multiple in (i * i..*max_value).step_by(i).skip(skip) {
let idx = multiple - min_value;
// SAFETY: `multiple` will always be between min_value and max_value
// (which define the length of the array), therfore idx is always smaller than the
// length of result, therefore this access is always in bounds.
// This is slightly faster than the bounds-checked write.
unsafe { *result.get_unchecked_mut(idx) = false };
}
}
result
}
fn calc_upper_limit(max_value: &usize) -> usize {
f64::sqrt(*max_value as f64).ceil() as usize
}
fn find_number_to_skip_until_min_value(min_value: &usize, i: usize) -> usize {
((min_value.saturating_sub(i * i)) as f64 / i as f64).ceil() as usize
}
pub fn remove(&mut self, num: &T) {
if let Some(index) = self.vector.iter().position(|x| x == num) {
self.vector.remove(index);
@@ -75,6 +91,11 @@ where
self.vector.len()
}
pub fn is_empty(&self) -> bool {
debug_assert_eq!(self.vector.len(), self.set.len());
self.vector.is_empty()
}
pub fn pop(&mut self) -> Option<T> {
let result = self.vector.pop();
if let Some(value) = result {
@@ -139,4 +160,11 @@ mod test {
let primes = Primes::get_between(2, 10_000_000);
assert_eq!(primes.len(), 664_579);
}
// #[ignore]
// #[test]
// fn test_performance_2() {
// let primes = Primes::get_between(2, 1_000_000_000);
// assert_eq!(primes.len(), 50_847_534);
// }
}