The following code was written to be a submission to this challenge on PPCG.
It uses this algorithm, the Meissal-Lehmer method. I follow the Wikipedia entry pretty naively, except I tried to memoize the phi function.
Please see @Shepmaster's answer for cleaned up, more idiomatic Rust.
I am looking for ways to improve speed. Most improvements I believe will come from optimizing the phi function, which is used recursively. Answers about making my code more idiomatic Rust are also welcome.
I've been compiling with cargo build --release
. The code runs in ~3 sec for input 1,000,000 and a lot longer for 10,000,000.
use std::env;
fn main() {
let args: Vec<_> = env::args().collect();
let x: usize = (args[1]).trim().parse()
.expect("expected a number");
let root: usize = (x as f64).sqrt() as usize;
let y: usize = (x as f64).powf(0.3333333333333) as usize + 1;
let sieve_size: usize = x/y+2;//y+1;
let mut sieve: Vec<bool> = vec![true; sieve_size ];
let mut primes: Vec<usize> = vec![0; sieve_size ];
sieve[0] = false; sieve[1] = false;
let mut a: usize = 0;
let mut num_primes = 1;
let mut num_primes_smaller_root: usize = 0;
// find all primes up to x/y ~ x^2/3 aka sieve_size
for i in 2..sieve_size {
if sieve[i] {
if i<= root {
if i<=y {
a+=1;
}
num_primes_smaller_root+=1;
}
primes[num_primes] = i;
num_primes +=1;
let mut multiples: usize = i;
while multiples < sieve_size {
sieve[multiples] = false;
multiples += i;
}
}
}
let mut phi_results: Vec<Vec<usize>> = vec![ vec![0; a+1 ];x+1 ];
let mut p_2: usize = 0;
for i in a+1..num_primes_smaller_root+1 {
let mut first_term: usize = 0;
while primes[first_term]< x/primes[i] {
//println!("checking {} vs {}...",primes[first_term],x/primes[i]);
first_term+=1;
}
if primes[first_term]==x/primes[i] {
first_term +=1;
}
p_2 += (first_term -1) - i + 1;
}
/*println!("y={}; a={}",y,a);
println!("P2 = {}",p_2);
println!("phi({},{}) = {}",x, a, phi(x,a,&primes));
*/
println!("pi({}) = {}", x, phi(x,a,&primes,&mut phi_results)+a-1-p_2);
}
fn phi(x:usize, b:usize, primes:&Vec<usize>, phi_results:&mut Vec<Vec<usize>>)->usize {
if b==0 {
return x;
}
if phi_results[x][b] != 0 {
return phi_results[x][b];
}
let value: usize = phi(x,b-1,primes,phi_results) - phi(x/primes[b],b-1,primes,phi_results);
phi_results[x][b] = value;
return value;
}
I'm kind of new to the site, so please let me know how to improve this post as a whole too, if necessary