Last active
April 14, 2020 10:13
-
-
Save eira-fransham/049922e22c41a5e37c22b7bc10364fcc to your computer and use it in GitHub Desktop.
Rust prime sieve, intended to be compiled to Wasm, combined with a `main.rs` which generates assert statements to test execution of the resultant WebAssembly.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pub fn sieve(limit: usize) -> Option<impl Iterator<Item = usize>> { | |
let mk_func = |cmpsts: Vec<_>| { | |
move |i| { | |
if i < 0 { | |
Some(2) | |
} else { | |
if cmpsts.get(i as usize >> 5)? & (1u32 << (i & 31)) == 0 { | |
Some((i + i + 3) as usize) | |
} else { | |
None | |
} | |
} | |
} | |
}; | |
if limit < 3 { | |
return Some((-1..limit as isize - 2).filter_map(mk_func(vec![]))); | |
} | |
let ndxlmt = (limit - 3) / 2 + 1; | |
let bfsz = ((limit - 3) / 2) / 32 + 1; | |
let mut cmpsts = vec![0u32; bfsz]; | |
let sqrtndxlmt = ((limit as f64).sqrt().ceil() as usize).saturating_sub(3) / 2 + 1; | |
for ndx in 0..sqrtndxlmt { | |
if (cmpsts.get(ndx >> 5)? & (1u32 << (ndx & 31))) == 0 { | |
let p = ndx + ndx + 3; | |
let mut cullpos = (p * p - 3) / 2; | |
while cullpos < ndxlmt { | |
*cmpsts.get_mut(cullpos >> 5)? |= 1u32 << (cullpos & 31); | |
cullpos += p; | |
} | |
} | |
} | |
Some((-1..ndxlmt as isize).filter_map(mk_func(cmpsts))) | |
} | |
#[no_mangle] | |
pub fn nth_prime(n: usize) -> usize { | |
let upper_bound = if n >= 6 { | |
let n = n as f64; | |
let log_n = n.log2(); | |
let log_log_n = log_n.log2(); | |
(n * log_n + n * log_log_n).ceil() as usize | |
} else { | |
20 | |
}; | |
if let Some(mut primes) = sieve(upper_bound) { | |
primes | |
.nth(n) | |
.unwrap_or_else(|| panic!("{}, {}", upper_bound, n)) | |
} else { | |
std::usize::MAX | |
} | |
} | |
#[no_mangle] | |
pub fn is_prime(n: usize) -> u8 { | |
if let Some(primes) = sieve(n) { | |
if primes.last() == Some(n) { | |
1 | |
} else { | |
0 | |
} | |
} else { | |
std::u8::MAX | |
} | |
} | |
#[no_mangle] | |
pub fn assert_prime(n: usize) { | |
if is_prime(n) != 1 { | |
panic!() | |
} | |
} | |
#[no_mangle] | |
pub fn assert_not_prime(n: usize) { | |
if is_prime(n) != 0 { | |
panic!() | |
} | |
} | |
#[cfg(test)] | |
mod tests { | |
#[test] | |
fn nth_prime() { | |
for (i, prime) in super::sieve(1000).unwrap().enumerate() { | |
assert_eq!(prime, super::nth_prime(i)) | |
} | |
} | |
#[test] | |
fn is_prime() { | |
for prime in super::sieve(1000).unwrap() { | |
assert!(super::is_prime(prime) == 1) | |
} | |
} | |
#[test] | |
fn assert_prime() { | |
for prime in super::sieve(1000).unwrap() { | |
super::assert_prime(prime) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mod lib; | |
fn main() { | |
println!(); | |
for i in 0..1000 { | |
println!( | |
"(assert_return (invoke \"is_prime\" (i32.const 0x{:x})) (i32.const 0x{:x}))", | |
i, | |
crate::lib::is_prime(i), | |
); | |
} | |
for (i, prime) in crate::lib::sieve(1000).unwrap().enumerate() { | |
println!( | |
"(assert_return (invoke \"nth_prime\" (i32.const 0x{:x})) (i32.const 0x{:x}))", | |
i, prime, | |
) | |
} | |
for i in 0..1000 { | |
if crate::lib::is_prime(i) == 1 { | |
println!( | |
"(assert_return (invoke \"assert_prime\" (i32.const 0x{:x})))", | |
i, | |
); | |
} else { | |
println!( | |
"(assert_return (invoke \"assert_not_prime\" (i32.const 0x{:x})))", | |
i, | |
); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment