optimize sieve of Eratosthenes
This commit is contained in:
+37
-9
@@ -33,10 +33,14 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn from_array(array: Vec<bool>, min_value: &usize, max_value: &usize) -> Self {
|
fn from_array(array: Vec<bool>, min_value: &usize, max_value: &usize) -> Self {
|
||||||
let mut vector = Vec::new();
|
let number_of_primes = array.iter().filter(|b| **b).count();
|
||||||
let mut set = HashSet::new();
|
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 {
|
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();
|
let prime = FromPrimitive::from_usize(number).unwrap();
|
||||||
vector.push(prime);
|
vector.push(prime);
|
||||||
set.insert(prime);
|
set.insert(prime);
|
||||||
@@ -51,18 +55,30 @@ where
|
|||||||
let length = *max_value - *min_value;
|
let length = *max_value - *min_value;
|
||||||
let mut result = vec![true; length];
|
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 i in 2..upper_limit {
|
||||||
for multiple in ((i * i)..*max_value).step_by(i) {
|
let skip = Self::find_number_to_skip_until_min_value(min_value, i);
|
||||||
if &multiple < min_value {
|
|
||||||
continue;
|
for multiple in (i * i..*max_value).step_by(i).skip(skip) {
|
||||||
}
|
let idx = multiple - min_value;
|
||||||
result[multiple - min_value] = false;
|
// 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
|
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) {
|
pub fn remove(&mut self, num: &T) {
|
||||||
if let Some(index) = self.vector.iter().position(|x| x == num) {
|
if let Some(index) = self.vector.iter().position(|x| x == num) {
|
||||||
self.vector.remove(index);
|
self.vector.remove(index);
|
||||||
@@ -75,6 +91,11 @@ where
|
|||||||
self.vector.len()
|
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> {
|
pub fn pop(&mut self) -> Option<T> {
|
||||||
let result = self.vector.pop();
|
let result = self.vector.pop();
|
||||||
if let Some(value) = result {
|
if let Some(value) = result {
|
||||||
@@ -139,4 +160,11 @@ mod test {
|
|||||||
let primes = Primes::get_between(2, 10_000_000);
|
let primes = Primes::get_between(2, 10_000_000);
|
||||||
assert_eq!(primes.len(), 664_579);
|
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);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user