Skip to content

Commit 6edb44c

Browse files
committed
wip
1 parent 556b244 commit 6edb44c

File tree

1 file changed

+55
-28
lines changed

1 file changed

+55
-28
lines changed

src/lib.rs

+55-28
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ case, but slower in the long term as they do not use any caching of primes.
6363
#![doc(html_root_url = "https://wackywendell.github.io/primes/")]
6464

6565
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;
6868
use std::ops::Index;
6969
use std::slice;
7070

@@ -82,28 +82,49 @@ A prime generator, using the Trial Division method.
8282
Create with `let mut pset = TrialDivision::new()`, and then use `pset.iter()` to iterate over all
8383
primes.
8484
**/
85-
#[derive(Default)]
85+
#[derive(Default, Clone)]
8686
pub struct TrialDivision {
8787
lst: Vec<u64>,
8888
}
8989

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+
90110
/**
91111
A prime generator, using the Sieve of Eratosthenes method. This is asymptotically more efficient
92112
than the Trial Division method, but slower earlier on.
93113
94114
Create with `let mut pset = Sieve::new()`, and then use `pset.iter()` to iterate over all primes.
95115
**/
96-
#[derive(Default)]
116+
#[derive(Default, Clone)]
97117
pub struct Sieve {
98118
primes: Vec<u64>,
119+
wheel: Wheel30,
99120

100121
// Keys are composites, values are prime factors.
101122
//
102123
// Every prime is in here once.
103124
//
104125
// Each entry corresponds to the last composite "crossed off" by the given prime,
105126
// not including any composite less than the values in 'primes'.
106-
sieve: HashMap<u64, u64>,
127+
sieve: BinaryHeap<Reverse<(u64, u64)>>,
107128
}
108129

109130
/// An iterator over generated primes. Created by `PrimeSet::iter` or
@@ -152,45 +173,51 @@ impl PrimeSetBasics for TrialDivision {
152173
impl Sieve {
153174
/// A new prime generator, primed with 2 and 3
154175
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+
}
160181
}
161182

162183
// insert a prime and its composite. If the composite is already occupied, we'll increase
163184
// the composite by prime and put it there, repeating as necessary.
164185
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)));
175187
}
176188
}
177189

178190
impl PrimeSetBasics for Sieve {
179191
/// Finds one more prime, and adds it to the list
180192
fn expand(&mut self) {
181-
let mut nextp = *self.primes.last().unwrap();
193+
let mut nextp = self.wheel.next();
182194
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);
187198
self.primes.push(nextp);
188199
return;
189200
}
190-
Entry::Occupied(o) => *o.get(),
201+
Some(&Reverse(v)) => v,
191202
};
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+
}
194221
}
195222
}
196223

0 commit comments

Comments
 (0)