Skip to content

Commit 853ccec

Browse files
committed
ref: refactor sieve of eratosthenes implementation
1 parent 1d9c510 commit 853ccec

File tree

1 file changed

+73
-37
lines changed

1 file changed

+73
-37
lines changed

src/math/sieve_of_eratosthenes.rs

Lines changed: 73 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,89 @@
1+
/// Implements the Sieve of Eratosthenes algorithm to find all prime numbers up to a given limit.
2+
///
3+
/// # Arguments
4+
///
5+
/// * `num` - The upper limit up to which to find prime numbers (inclusive).
6+
///
7+
/// # Returns
8+
///
9+
/// A vector containing all prime numbers up to the specified limit.
110
pub fn sieve_of_eratosthenes(num: usize) -> Vec<usize> {
211
let mut result: Vec<usize> = Vec::new();
3-
if num == 0 {
4-
return result;
12+
if num >= 2 {
13+
let mut sieve: Vec<bool> = vec![true; num + 1];
14+
15+
// 0 and 1 are not prime numbers
16+
sieve[0] = false;
17+
sieve[1] = false;
18+
19+
let end: usize = (num as f64).sqrt() as usize;
20+
21+
// mark non-prime numbers in the sieve
22+
update_sieve(&mut sieve, end, num);
23+
24+
// collect all prime numbers
25+
result = extract_primes(&sieve);
526
}
6-
let mut start: usize = 2;
7-
let end: usize = (num as f64).sqrt() as usize;
8-
let mut sieve: Vec<bool> = vec![true; num + 1];
27+
result
28+
}
929

10-
while start <= end {
30+
/// Marks non-prime numbers in the sieve.
31+
///
32+
/// # Arguments
33+
///
34+
/// * `sieve` - A mut slice of booleans representing the sieve.
35+
/// * `end` - The square root of the upper limit, used to optimize the algorithm.
36+
/// * `num` - The upper limit up to which to mark non-prime numbers.
37+
fn update_sieve(sieve: &mut [bool], end: usize, num: usize) {
38+
for start in 2..=end {
1139
if sieve[start] {
12-
result.push(start);
13-
for i in (start * start..num + 1).step_by(start) {
14-
if sieve[i] {
15-
sieve[i] = false;
16-
}
40+
for i in (start * start..=num).step_by(start) {
41+
sieve[i] = false;
1742
}
1843
}
19-
start += 1;
20-
}
21-
for (i, item) in sieve.iter().enumerate().take(num + 1).skip(end + 1) {
22-
if *item {
23-
result.push(i)
24-
}
2544
}
26-
result
45+
}
46+
47+
/// Extracts prime numbers from the sieve.
48+
///
49+
/// # Arguments
50+
///
51+
/// * `sieve` - A slice of booleans representing the sieve with non-prime numbers marked as false.
52+
///
53+
/// # Returns
54+
///
55+
/// A vector containing all prime numbers extracted from the sieve.
56+
fn extract_primes(sieve: &[bool]) -> Vec<usize> {
57+
sieve
58+
.into_iter()
59+
.enumerate()
60+
.filter_map(|(num, is_prime)| if *is_prime { Some(num) } else { None })
61+
.collect()
2762
}
2863

2964
#[cfg(test)]
3065
mod tests {
3166
use super::*;
3267

33-
#[test]
34-
fn basic() {
35-
assert_eq!(sieve_of_eratosthenes(0), vec![]);
36-
assert_eq!(sieve_of_eratosthenes(11), vec![2, 3, 5, 7, 11]);
37-
assert_eq!(
38-
sieve_of_eratosthenes(25),
39-
vec![2, 3, 5, 7, 11, 13, 17, 19, 23]
40-
);
41-
assert_eq!(
42-
sieve_of_eratosthenes(33),
43-
vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
44-
);
45-
assert_eq!(
46-
sieve_of_eratosthenes(100),
47-
vec![
48-
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79,
49-
83, 89, 97
50-
]
51-
);
68+
macro_rules! sieve_tests {
69+
($($name:ident: $test_case:expr,)*) => {
70+
$(
71+
#[test]
72+
fn $name() {
73+
let (input, expected) = $test_case;
74+
assert_eq!(sieve_of_eratosthenes(input), expected);
75+
}
76+
)*
77+
}
78+
}
79+
80+
sieve_tests! {
81+
test_0: (0, Vec::<usize>::new()),
82+
test_11: (11, vec![2, 3, 5, 7, 11]),
83+
test_25: (25, vec![2, 3, 5, 7, 11, 13, 17, 19, 23]),
84+
test_33: (33, vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]),
85+
test_100: (100, vec![
86+
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97
87+
]),
5288
}
5389
}

0 commit comments

Comments
 (0)