2
\$\begingroup\$

Linq's AsParallel() call would be my normal way of doing something like this, but Rust hasn't stolen that just yet. This method has obvious shortcomings, but I'm still sort of hoping for it to shave off a little time by engaging a second core.

How can I achieve this less terribly?

use std::num::Float;
use std::sync::Future;

fn main() {
    // This implementation cheats because it knows the biggest prime value
    // in the range: 7919. Getting primes in parallel is a pain in the ass 
    // pretty much no matter what, and it's probably not worth it, but on 
    // the up side... Eh. Whatever. Only other way I know to do this would 
    // be to get the first *1001* primes, sort them, and then fold the first 
    // thousand after stuffing them into a vector.

    let mut path_1 = Future::spawn(proc() {
        Unfold::new(3, incr).filter(prime).take_while(|n| *n <= 7919).fold(0i, |a, b| a + b)
    });
    let mut path_2 = Future::spawn(proc() {
        Unfold::new(5, incr).filter(prime).take_while(|n| *n <= 7919).fold(0i, |a, b| a + b)
    });

    // As you can see, my plan here was to get 999 primes (skipping 2) 
    // and then add 2 back in later on.
    println!("{}", path_1.get() + path_2.get() + 2);
}

fn incr(n: &mut int) -> Option<int> {
    let r = Some(*n);
    *n = *n + 4; 
    r
}

fn prime(n: &int) -> bool {
    match n {
        &1 => false,
        &2 => true,
        &3 => true,
        n if *n % 2 == 0 => false,
        _ => {
            let max = (*n as f64).sqrt() as int + 1;
            !range(2, max).any(|i| *n % i == 0)
        }
    }
}
\$\endgroup\$
1
\$\begingroup\$

It isn't clear to me what you are asking. However, I was able to update your code and run it:

use std::thread;

struct PrimeIncrement(i64);

impl Iterator for PrimeIncrement {
    type Item = i64;
    fn next(&mut self) -> Option<i64> {
        self.0 += 4; // What do you mean "integer overflow"? ^_^
        Some(self.0)
    }
}

fn main() {
    let path_1 = thread::scoped(|| {
        PrimeIncrement(3).filter(prime).take_while(|&n| n <= 7919).fold(0, |a, b| a + b)
    });
    let path_2 = thread::scoped(|| {
        PrimeIncrement(5).filter(prime).take_while(|&n| n <= 7919).fold(0, |a, b| a + b)
    });

    let a = path_1.join();
    let b = path_2.join();

    println!("{}", 2 + a + b);
}

fn prime(n: &i64) -> bool {
    match n {
        &1 => false,
        &2 => true,
        &3 => true,
        n if *n % 2 == 0 => false,
        _ => {
            let max = (*n as f64).sqrt() as i64 + 1;
            !(2..max).any(|i| *n % i == 0)
        }
    }
}

The main changes were:

  1. Removing Unfold, as it isn't stable in the 1.0 beta.
  2. Using thread::scoped instead of a Future.
  3. Using i64 instead of int

Update for Rust 1.3

The thread::scoped API was found to have soundness problems and has been deprecated. In this case, thread::spawn is powerful enough, so I've replaced that:

use std::thread;

struct PrimeIncrement(i64);

impl Iterator for PrimeIncrement {
    type Item = i64;
    fn next(&mut self) -> Option<i64> {
        self.0 += 4; // What do you mean "integer overflow"? ^_^
        Some(self.0)
    }
}

fn main() {
    let path_1 = thread::spawn(|| {
        PrimeIncrement(3).filter(prime).take_while(|&n| n <= 7919).fold(0, |a, b| a + b)
    });
    let path_2 = thread::spawn(|| {
        PrimeIncrement(5).filter(prime).take_while(|&n| n <= 7919).fold(0, |a, b| a + b)
    });

    let a = path_1.join().unwrap();
    let b = path_2.join().unwrap();

    println!("{}", 2 + a + b);
}

fn prime(n: &i64) -> bool {
    match *n {
        1 => false,
        2 => true,
        3 => true,
        n if n % 2 == 0 => false,
        n => {
            let max = (n as f64).sqrt() as i64 + 1;
            !(2..max).any(|i| n % i == 0)
        }
    }
}

Additionally, I now match on *n, which avoids the need to have quite as many dereferences.

\$\endgroup\$
3
  • \$\begingroup\$ The original code ran already, at least back when I asked that question. It was in December, after all. \$\endgroup\$
    – archer884
    Apr 6 '15 at 2:07
  • \$\begingroup\$ @archer884 maybe you can clarify your question - I still don't know what you would like to get from a code review. \$\endgroup\$
    – Shepmaster
    Apr 6 '15 at 2:08
  • \$\begingroup\$ I asked for a cleaner way to distribute work across several cores. The short answer is that Rust doesn't currently have a clean, easy way to do that. I realize that now, but I was not aware of that back in December of 2014. \$\endgroup\$
    – archer884
    Apr 6 '15 at 5:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.