@@ -63,8 +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
+ use std:: cmp :: Reverse ;
67
+ use std:: collections:: BinaryHeap ;
68
68
use std:: ops:: Index ;
69
69
use std:: slice;
70
70
@@ -82,28 +82,49 @@ A prime generator, using the Trial Division method.
82
82
Create with `let mut pset = TrialDivision::new()`, and then use `pset.iter()` to iterate over all
83
83
primes.
84
84
**/
85
- #[ derive( Default ) ]
85
+ #[ derive( Default , Clone ) ]
86
86
pub struct TrialDivision {
87
87
lst : Vec < u64 > ,
88
88
}
89
89
90
+ const WHEEL30 : [ u64 ; 8 ] = [ 1 , 7 , 11 , 13 , 17 , 19 , 23 , 29 ] ;
91
+
92
+ #[ derive( Default , Copy , Clone ) ]
93
+ struct Wheel30 {
94
+ base : u64 ,
95
+ ix : usize ,
96
+ }
97
+
98
+ impl Wheel30 {
99
+ pub fn next ( & mut self ) -> u64 {
100
+ let value = self . base + WHEEL30 [ self . ix ] ;
101
+ self . ix += 1 ;
102
+ if self . ix >= WHEEL30 . len ( ) {
103
+ self . ix = 0 ;
104
+ self . base += 30 ;
105
+ }
106
+ value
107
+ }
108
+ }
109
+
90
110
/**
91
111
A prime generator, using the Sieve of Eratosthenes method. This is asymptotically more efficient
92
112
than the Trial Division method, but slower earlier on.
93
113
94
114
Create with `let mut pset = Sieve::new()`, and then use `pset.iter()` to iterate over all primes.
95
115
**/
96
- #[ derive( Default ) ]
116
+ #[ derive( Default , Clone ) ]
97
117
pub struct Sieve {
98
118
primes : Vec < u64 > ,
119
+ wheel : Wheel30 ,
99
120
100
121
// Keys are composites, values are prime factors.
101
122
//
102
123
// Every prime is in here once.
103
124
//
104
125
// Each entry corresponds to the last composite "crossed off" by the given prime,
105
126
// not including any composite less than the values in 'primes'.
106
- sieve : HashMap < u64 , u64 > ,
127
+ sieve : BinaryHeap < Reverse < ( u64 , u64 ) > > ,
107
128
}
108
129
109
130
/// An iterator over generated primes. Created by `PrimeSet::iter` or
@@ -152,45 +173,51 @@ impl PrimeSetBasics for TrialDivision {
152
173
impl Sieve {
153
174
/// A new prime generator, primed with 2 and 3
154
175
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 }
176
+ Sieve {
177
+ primes : vec ! [ 2 , 3 , 5 ] ,
178
+ sieve : BinaryHeap :: new ( ) ,
179
+ wheel : Wheel30 { base : 0 , ix : 1 } ,
180
+ }
160
181
}
161
182
162
183
// insert a prime and its composite. If the composite is already occupied, we'll increase
163
184
// the composite by prime and put it there, repeating as necessary.
164
185
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
- }
186
+ self . sieve . push ( Reverse ( ( composite, prime) ) ) ;
175
187
}
176
188
}
177
189
178
190
impl PrimeSetBasics for Sieve {
179
191
/// Finds one more prime, and adds it to the list
180
192
fn expand ( & mut self ) {
181
- let mut nextp = * self . primes . last ( ) . unwrap ( ) ;
193
+ let mut nextp = self . wheel . next ( ) ;
182
194
loop {
183
- nextp += 2 ;
184
- let factor = match self . sieve . entry ( nextp) {
185
- Entry :: Vacant ( _) => {
186
- self . sieve . insert ( nextp * nextp, nextp) ;
195
+ let ( composite, factor) = match self . sieve . peek ( ) {
196
+ None => {
197
+ self . insert ( nextp, nextp * nextp) ;
187
198
self . primes . push ( nextp) ;
188
199
return ;
189
200
}
190
- Entry :: Occupied ( o ) => * o . get ( ) ,
201
+ Some ( & Reverse ( v ) ) => v ,
191
202
} ;
192
-
193
- self . insert ( factor, nextp + 2 * factor) ;
203
+ match composite. cmp ( & nextp) {
204
+ Less => {
205
+ let _ = self . sieve . pop ( ) ;
206
+ self . insert ( factor, composite + 2 * factor) ;
207
+ }
208
+ Equal => {
209
+ let _ = self . sieve . pop ( ) ;
210
+ self . insert ( factor, composite + 2 * factor) ;
211
+ // 'nextp' isn't prime, so move to one that might be
212
+ nextp = self . wheel . next ( ) ;
213
+ }
214
+ Greater => {
215
+ // nextp is prime!
216
+ self . insert ( nextp, nextp * nextp) ;
217
+ self . primes . push ( nextp) ;
218
+ return ;
219
+ }
220
+ }
194
221
}
195
222
}
196
223
0 commit comments