@@ -63,6 +63,8 @@ case, but slower in the long term as they do not use any caching of primes.
63
63
#![ doc( html_root_url = "https://wackywendell.github.io/primes/" ) ]
64
64
65
65
use std:: cmp:: Ordering :: { Equal , Greater , Less } ;
66
+ use std:: collections:: hash_map:: Entry ;
67
+ use std:: collections:: HashMap ;
66
68
use std:: ops:: Index ;
67
69
use std:: slice;
68
70
@@ -85,6 +87,25 @@ pub struct TrialDivision {
85
87
lst : Vec < u64 > ,
86
88
}
87
89
90
+ /**
91
+ A prime generator, using the Sieve of Eratosthenes method. This is asymptotically more efficient
92
+ than the Trial Division method, but slower earlier on.
93
+
94
+ Create with `let mut pset = Sieve::new()`, and then use `pset.iter()` to iterate over all primes.
95
+ **/
96
+ #[ derive( Default ) ]
97
+ pub struct Sieve {
98
+ primes : Vec < u64 > ,
99
+
100
+ // Keys are composites, values are prime factors.
101
+ //
102
+ // Every prime is in here once.
103
+ //
104
+ // Each entry corresponds to the last composite "crossed off" by the given prime,
105
+ // not including any composite less than the values in 'primes'.
106
+ sieve : HashMap < u64 , u64 > ,
107
+ }
108
+
88
109
/// An iterator over generated primes. Created by `PrimeSet::iter` or
89
110
/// `PrimeSet::generator`
90
111
pub struct PrimeSetIter < ' a , P : PrimeSet > {
@@ -103,7 +124,7 @@ impl TrialDivision {
103
124
impl PrimeSetBasics for TrialDivision {
104
125
/// Finds one more prime, and adds it to the list
105
126
fn expand ( & mut self ) {
106
- let mut l: u64 = self . lst [ self . lst . len ( ) - 1 ] + 2 ;
127
+ let mut l: u64 = self . lst . last ( ) . unwrap ( ) + 2 ;
107
128
let mut remainder = 0 ;
108
129
loop {
109
130
for & n in & self . lst {
@@ -128,6 +149,57 @@ impl PrimeSetBasics for TrialDivision {
128
149
}
129
150
}
130
151
152
+ impl Sieve {
153
+ /// A new prime generator, primed with 2 and 3
154
+ pub fn new ( ) -> Sieve {
155
+ let primes = vec ! [ 2 , 3 ] ;
156
+ let mut sieve = HashMap :: new ( ) ;
157
+ sieve. insert ( 9 , 3 ) ;
158
+
159
+ Sieve { primes, sieve }
160
+ }
161
+
162
+ // insert a prime and its composite. If the composite is already occupied, we'll increase
163
+ // the composite by prime and put it there, repeating as necessary.
164
+ fn insert ( & mut self , prime : u64 , composite : u64 ) {
165
+ for n in 0 .. {
166
+ // We can skip composite + prime, because its even, so go straight to
167
+ // composite + 2*prime. If that's already "crossed off" (in self.sieve),
168
+ // go on to composite + 4*prime and so on.
169
+ let value = composite + prime * 2 * n;
170
+ if let Entry :: Vacant ( v) = self . sieve . entry ( value) {
171
+ v. insert ( prime) ;
172
+ return ;
173
+ }
174
+ }
175
+ }
176
+ }
177
+
178
+ impl PrimeSetBasics for Sieve {
179
+ /// Finds one more prime, and adds it to the list
180
+ fn expand ( & mut self ) {
181
+ let mut nextp = * self . primes . last ( ) . unwrap ( ) ;
182
+ loop {
183
+ nextp += 2 ;
184
+ let factor = match self . sieve . entry ( nextp) {
185
+ Entry :: Vacant ( _) => {
186
+ self . sieve . insert ( nextp * nextp, nextp) ;
187
+ self . primes . push ( nextp) ;
188
+ return ;
189
+ }
190
+ Entry :: Occupied ( o) => * o. get ( ) ,
191
+ } ;
192
+
193
+ self . insert ( factor, nextp + 2 * factor) ;
194
+ }
195
+ }
196
+
197
+ /// Return all primes found so far as a slice
198
+ fn list ( & self ) -> & [ u64 ] {
199
+ & self . primes [ ..]
200
+ }
201
+ }
202
+
131
203
pub trait PrimeSet : PrimeSetBasics + Sized {
132
204
/// Number of primes found so far
133
205
fn len ( & self ) -> usize {
0 commit comments