Skip to content

Instantly share code, notes, and snippets.

@eira-fransham
Last active April 14, 2020 10:13
Show Gist options
  • Save eira-fransham/049922e22c41a5e37c22b7bc10364fcc to your computer and use it in GitHub Desktop.
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.
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)
}
}
}
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