Compare commits

...

3 Commits

Author SHA1 Message Date
fd36faae13
[code] remove unnecessary reference 2024-09-28 12:59:31 +02:00
490c53a280
[fix] but primes behind an Arc
- don't clone primes for every thread, instead put it behind an Arc
  (atomic reference counted)
- print the pure calculation time at the end of the program
- don't show thread debug prints
2024-09-28 12:57:29 +02:00
939e239b36
[feature] use multiple threads to calculate chunks in parallel 2024-09-12 20:35:23 +02:00
4 changed files with 90 additions and 9 deletions

20
Cargo.lock generated
View File

@ -2,6 +2,24 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "hcn"
version = "1.0.0"
version = "1.0.0-multithread"
dependencies = [
"itertools",
]
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]

View File

@ -1,9 +1,10 @@
[package]
name = "hcn"
version = "1.0.0"
version = "1.0.0-multithread"
edition = "2021"
[dependencies]
itertools = "0.13"
[lints.rust]
unsafe_code = "forbid"

View File

@ -1,7 +1,14 @@
mod sieve;
use std::time::Instant;
use std::{
collections::HashMap,
env,
sync::Arc,
thread::{self, available_parallelism},
time::Instant,
};
use itertools::Itertools as _;
use sieve::get_primes;
const MAX_SIEVED_PRIMES: usize = 100_000_000;
@ -44,21 +51,76 @@ fn prime_factors(nr: u64, primes: &[u64]) -> u64 {
num_teilers
}
fn the_thread(mut start: u64, end: u64, primes: &[u64]) -> HashMap<u64, u64> {
let mut max_teilers = 0;
let mut max_teilers_hashmap = HashMap::new();
let mut step_size = 10;
if start == 0 {
start = 2;
step_size = 2;
}
for nr in (start..=end).step_by(step_size) {
let teilers = prime_factors(nr, primes);
if teilers > max_teilers {
max_teilers = teilers;
max_teilers_hashmap.insert(nr, teilers);
}
}
max_teilers_hashmap
}
fn calculate_chunk_bounds(i: usize, num_threads: usize, max_nr: usize) -> (usize, usize) {
let chunk_size = max_nr / num_threads;
let start = i * chunk_size;
let end = ((i + 1) * chunk_size).min(max_nr);
(start, end)
}
fn main() {
let max_nr = env::args()
.nth(1)
.expect("Usage: hcn <max_nr>")
.parse::<usize>()
.expect("Invalid max_nr");
let start = Instant::now();
println!("Precalculating primes...");
let primes = get_primes(MAX_SIEVED_PRIMES);
println!("{} primes. Took {:?}", primes.len(), start.elapsed());
let primes = Arc::new(primes);
#[allow(clippy::unwrap_used)]
let num_threads = available_parallelism().unwrap().get();
let mut threads = Vec::with_capacity(num_threads);
let now = Instant::now();
for i in 0..num_threads {
let (start, end) = calculate_chunk_bounds(i, num_threads, max_nr);
let primes = primes.clone();
threads.push(thread::spawn(move || {
the_thread(start as u64, end as u64, &primes)
}));
}
let mut results = HashMap::new();
for thread in threads {
let thread_result = thread.join().expect("Thread failed to join (panicked?)");
results.extend(thread_result);
}
let mut max_teilers = 0;
let start = Instant::now();
for nr in (2..1_000_000_000).step_by(2) {
let teilers = prime_factors(nr, &primes);
for (nr, teilers) in results.into_iter().sorted() {
if teilers > max_teilers {
println!("{nr}: {teilers} ({:?} since start)", start.elapsed());
println!("{nr}: {teilers}");
max_teilers = teilers;
}
}
println!("Took {:?}", now.elapsed());
}

View File

@ -29,7 +29,7 @@ fn find_next_prime(nr: &mut u64, sieve: &mut [bool]) -> Option<u64> {
.iter()
.enumerate()
.skip(start_idx)
.find(|&(_, &is_prime)| is_prime)
.find(|(_, &is_prime)| is_prime)
{
*nr = idx as u64;
return Some(*nr);