primal_sieve/streaming/
primes.rs

1use crate::wheel;
2use crate::streaming::{self, StreamingSieve};
3
4#[cfg(target_pointer_width = "32")]
5const SQRT: usize = 1 << 16;
6#[cfg(target_pointer_width = "64")]
7const SQRT: usize = 1 << 32;
8
9enum Early {
10    Two,
11    Three,
12    Five,
13    Done,
14}
15
16/// An iterator over all primes.
17///
18/// This will yield primes indefinitely (bits in `usize`
19/// permitting). If there is an known upper bound, sieving first with
20/// `Sieve` and using its `primes_from` method may be more efficient,
21/// especially if the bound is small.
22///
23/// This requires *O(sqrt(p))* memory to yield prime `p`, where `X` is
24/// the maximum value of `usize`.
25///
26/// # Examples
27///
28/// ```rust
29/// let count = primal::Primes::all().take_while(|p| *p < 1_000_000).count();
30/// println!("{}", count);
31/// ```
32pub struct Primes {
33    early: Early,
34    base: usize,
35    ones: primal_bit::IntoOnes,
36    streaming: StreamingSieve,
37    sieving_primes: Option<Box<Primes>>,
38    left_over: Option<usize>,
39}
40
41impl Primes {
42    /// The sequence `2, 3, 5, 7, 11, ...`.
43    ///
44    /// # Examples
45    ///
46    /// ```rust
47    /// // print the first 20 primes
48    /// for p in primal::Primes::all().take(20) {
49    ///     println!("{}", p);
50    /// }
51    /// ```
52    pub fn all() -> Primes {
53        Primes::sqrt(SQRT)
54    }
55
56    fn sqrt(sqrt: usize) -> Primes {
57        let (sieving, limit) = if sqrt < streaming::isqrt(streaming::SEG_LEN) {
58            (None, sqrt * sqrt)
59        } else {
60            (Some(Box::new(Primes::sqrt(streaming::isqrt(sqrt)))),
61             streaming::SEG_LEN)
62        };
63        let mut streaming = StreamingSieve::new(limit);
64
65        let ones = {
66            let (_, bits) = streaming.next().unwrap();
67            bits.clone().into_ones()
68        };
69
70        // we manually add the primes
71        streaming.small = None;
72        // go to the end.
73        streaming.limit = !0;
74
75        Primes {
76            early: Early::Two,
77            base: 0,
78            ones,
79            streaming,
80            sieving_primes: sieving,
81            left_over: None,
82        }
83    }
84
85    #[inline]
86    fn from_bit_index(&self, i: usize) -> Option<usize> {
87        let w = wheel::from_bit_index(i);
88        self.base.checked_add(w)
89    }
90
91    fn advance_ones(&mut self) -> bool {
92        let low = self.streaming.low;
93        let high = low.saturating_add(streaming::SEG_LEN);
94
95        for q in self.left_over.into_iter().chain(self.sieving_primes.as_mut().unwrap()) {
96            if q.saturating_mul(q) >= high {
97                self.left_over = Some(q);
98                break
99            }
100            if q > streaming::isqrt(streaming::SEG_LEN) {
101                self.streaming.add_sieving_prime(q, low);
102            }
103        }
104
105        match self.streaming.next() {
106            Some((_, bits)) => {
107                self.base = low;
108                self.ones = bits.clone().into_ones();
109                true
110            },
111            None => false,
112        }
113    }
114}
115
116// See also `Iterator for SievePrimes` with nearly identical code.
117impl Iterator for Primes {
118    type Item = usize;
119
120    #[inline]
121    fn next(&mut self) -> Option<usize> {
122        match self.early {
123            Early::Done => {}
124            Early::Two => {
125                self.early = Early::Three;
126                return Some(2)
127            }
128            Early::Three => {
129                self.early = Early::Five;
130                return Some(3)
131            }
132            Early::Five => {
133                self.early = Early::Done;
134                return Some(5)
135            }
136        }
137
138        loop {
139            if let Some(i) = self.ones.next() {
140                return self.from_bit_index(i);
141            }
142            if !self.advance_ones() {
143                return None;
144            }
145        }
146    }
147
148    fn fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc
149    where
150        F: FnMut(Acc, Self::Item) -> Acc
151    {
152        match self.early {
153            Early::Done => {}
154            Early::Two => {
155                acc = f(acc, 2);
156                acc = f(acc, 3);
157                acc = f(acc, 5);
158            }
159            Early::Three => {
160                acc = f(acc, 3);
161                acc = f(acc, 5);
162            }
163            Early::Five => {
164                acc = f(acc, 5);
165            }
166        }
167        loop {
168            while let Some(i) = self.ones.next() {
169                match self.from_bit_index(i) {
170                    Some(p) => acc = f(acc, p),
171                    None => return acc,
172                }
173            }
174            if !self.advance_ones() {
175                return acc;
176            }
177        }
178    }
179}
180
181#[cfg(test)]
182mod tests {
183    use crate::Sieve;
184    use super::Primes;
185
186    fn check_equality(limit: usize) {
187        let sieve = Sieve::new(limit);
188
189        let real = sieve.primes_from(0).take_while(|x| *x < limit);
190        let computed = Primes::all().take_while(|x| *x < limit);
191
192        let mut i = 0;
193        for (r, c) in real.zip(computed) {
194            assert_eq!(c, r);
195            i += 1;
196        }
197        assert_eq!(sieve.prime_pi(limit), i);
198    }
199
200    #[test]
201    fn equality() {
202        check_equality(20_000_000);
203    }
204
205    #[test]
206    fn equality_huge() {
207        let limit = if cfg!(feature = "slow_tests") {
208            // This takes a minute or so in debug mode, but it does work!
209            ::std::u32::MAX as usize
210        } else {
211            100_000_000
212        };
213        check_equality(limit);
214    }
215
216    #[test]
217    #[should_panic = "123456791"]
218    fn fold() {
219        // There's no termination until we exceed `usize::MAX`, which
220        // will take too long, but we can cut it short by unwinding.
221        Primes::all().fold((), |(), p| {
222            if p > 123456789 {
223                panic!("{}", p);
224            }
225        })
226    }
227}