diff --git a/Cargo.lock b/Cargo.lock index b2a75c2..e16ef91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,15 @@ version = 3 [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "cfg-if" @@ -16,9 +22,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -31,30 +37,28 @@ version = "0.1.0" dependencies = [ "num", "num-bigint", + "once_cell", "rand", "thread-priority", ] [[package]] name = "libc" -version = "0.2.139" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "log" -version = "0.4.17" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "num" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ "num-bigint", "num-complex", @@ -66,39 +70,37 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-complex" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", ] [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -107,11 +109,10 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", "num-bigint", "num-integer", "num-traits", @@ -119,13 +120,19 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -164,16 +171,17 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.11" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "thread-priority" -version = "0.12.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ee4429f2c3bbeafa7136ea54d75a5f38b02e4f006c0b310f07e35c3b49eb3e7" +checksum = "0d3b04d33c9633b8662b167b847c7ab521f83d1ae20f2321b65b5b925e532e36" dependencies = [ + "bitflags", "cfg-if", "libc", "log", diff --git a/Cargo.toml b/Cargo.toml index 600baaf..d8c920e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,13 +6,17 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -num = "0.4.0" -thread-priority = "0.12.0" -rand = "0.8.5" -num-bigint= { default-features = false, version = "0.4.3" } +num = "0.4" +thread-priority = "1.1" +rand = "0.8" +num-bigint= { default-features = false, version = "0.4" } +once_cell = "1.19" [profile.release] lto = true # Enable link-time optimization codegen-units = 1 # Reduce number of codegen units to increase optimizations panic = 'abort' # Abort on panic -strip = true # Strip symbols from binary; remove pdb \ No newline at end of file +strip = true # Strip symbols from binary; remove pdb + +[profile.dev] +opt-level = 3 \ No newline at end of file diff --git a/src/is_prime.rs b/src/is_prime.rs index 632f3e0..25ac707 100644 --- a/src/is_prime.rs +++ b/src/is_prime.rs @@ -1,73 +1,66 @@ - - pub mod prime_utils { use num::{BigUint, One, Zero}; use crate::primality_test::primality_tests::is_probably_prime; - #[must_use] pub fn log_2(x: &BigUint) -> u64 { + #[must_use] + pub fn log_2(x: &BigUint) -> u64 { x.bits() - 1 } - - #[must_use] pub fn is_prime(number: &BigUint, g_primes: &Vec) -> bool { + + #[must_use] + pub fn is_prime(number: &BigUint, g_primes: &Vec) -> bool { if BigUint::from(1u8) == *number { return false; } - if BigUint::from(4u8) > *number { + if BigUint::from(4u8) > *number { return true; } if number.sqrt().pow(2) == *number { return false; } - + let two = BigUint::from(2u8); - + // number = 2^a - 1 // a = log2(number + 1) - let a = log_2(&(number+1u8)); - if BigUint::from(2u8).pow(a as u32)-BigUint::one() != *number { + let a = log_2(&(number + 1u8)); + if BigUint::from(2u8).pow(a as u32) - BigUint::one() != *number { let mut i = BigUint::one(); let one = BigUint::one(); let zero = BigUint::zero(); - - let sqrtnum = number.sqrt()+&one; //fake ceil function - if let Some(max_value) = g_primes.iter().max() { - if max_value > &sqrtnum { - for prime in g_primes { - if prime<&sqrtnum && number%prime == zero { - return false; - } - } + let sqrtnum = number.sqrt() + &one; //fake ceil function + + for prime in g_primes { + if prime < &sqrtnum && number % prime == zero { + return false; } } - if !is_probably_prime(number,5) { + if !is_probably_prime(number, 5) { return false; } loop { i += &one; - if number%&i == zero { + if number % &i == zero { return false; } if i == sqrtnum { return true; } } - - } - + // 4 12 194 let mut last = BigUint::from(4u8); - + for _i in 2..a { - last = (last.pow(2)-&two)%number; + last = (last.pow(2) - &two) % number; } last == BigUint::from(0u8) } } - diff --git a/src/main.rs b/src/main.rs index 001e1eb..14c077a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,29 +1,33 @@ #![warn(clippy::perf)] #![warn(clippy::all)] - pub mod is_prime; pub mod primality_test; -use std::{time::SystemTime,thread, io::Write}; -use num::{BigUint, One}; use crate::is_prime::prime_utils; -use thread_priority::{set_current_thread_priority,ThreadPriority}; +use num::{BigUint, One}; +use once_cell::sync::Lazy; +use std::{ + io::Write, + sync::atomic::{AtomicI64, AtomicUsize}, + thread, + time::SystemTime, +}; + +#[cfg(target_os = "windows")] +use thread_priority::{set_current_thread_priority, ThreadPriority}; fn p(n: f64) -> f64 { let ln_n = n.ln(); let ln_ln_n = ln_n.ln(); let ln_ln_ln_n = ln_ln_n.ln(); - n * ( - ln_n + ln_ln_n - 1.0 - + (ln_ln_ln_n - 2.0) / ln_n + n * (ln_n + ln_ln_n - 1.0 + (ln_ln_ln_n - 2.0) / ln_n - ((ln_ln_n).powi(2) - 6.0 * ln_ln_n + 11.0) / (2.0 * 2.0f64.log2() * ln_n) - + ((ln_ln_n / ln_n).powi(3)) * (1.0 / ln_n) - ) + + ((ln_ln_n / ln_n).powi(3)) * (1.0 / ln_n)) } -fn to_usize(f:f64) -> usize { +fn to_usize(f: f64) -> usize { let rounded_num: i64 = f.round() as i64; if rounded_num >= 0 { rounded_num as usize @@ -32,13 +36,15 @@ fn to_usize(f:f64) -> usize { } } -fn to_f64(u:usize) -> f64 { +fn to_f64(u: usize) -> f64 { f64::from_bits(u as u64) } fn try_set_thread_priority() { - if set_current_thread_priority(ThreadPriority::Max).is_err() { + #[cfg(target_os = "windows")] + if let Err(e) = set_current_thread_priority(ThreadPriority::Max) { eprintln!("[WARN] failed to set thread priority to max"); + eprintln!("{e}"); } } @@ -55,103 +61,114 @@ fn write_primes(primes: &[BigUint]) { file.write_all(b"]").unwrap(); } - -/* - let mut buffer = String::new(); - let stdin = io::stdin(); - print!("please enter the number to check: "); - io::stdout().flush().expect("could not flush"); - stdin.read_line(&mut buffer).expect("could not read from stdin"); - buffer = buffer.trim().to_owned(); - - let number = BigUint::parse_bytes(&buffer.as_bytes(), 10).expect("expected positive number"); - - if is_prime(number.clone()) { - println!("\n{number} is a prime"); - } else { - println!("\n{number} is not a prime"); - } - */ fn main() { - const N:i64 = 100_000; - const NU:usize = N as usize; + const N: i64 = 1_000_000; + const NF: f64 = N as f64; + const NU: usize = N as usize; const THREADS: usize = 12; - const SPLITTER: u128 = 10000u128; + const SPLITTER: u64 = N as u64 / 10; try_set_thread_priority(); let sys_time = SystemTime::now(); - let nf:f64 = 100_000f64; - let nthprime_approx:usize = to_usize(p(nf*1.02)); - - let workloads = nthprime_approx/THREADS; + let nthprime_approx: usize = to_usize(p(NF * 1.02)); - let primecache: Vec = vec![]; + let workloads = nthprime_approx / THREADS; + + let primecache: Vec = Vec::with_capacity(NU); let primemutex = std::sync::Mutex::new(primecache); let primearc = std::sync::Arc::new(primemutex); - let mut joins = vec![]; - for i in 0..THREADS { - let arcclone = primearc.clone(); - let handle = thread::spawn(move || { - try_set_thread_priority(); + let progress_val = AtomicI64::new(0); + let progress = &progress_val; - let one_thousand = &BigUint::from(SPLITTER*10); - let one_hundred = &BigUint::from(SPLITTER); - let ten = &BigUint::from(10u8); + let threads_done_val = AtomicUsize::new(0); + let threads_done = &threads_done_val; - let work_uint = BigUint::from(workloads); - let mut number = BigUint::from(i)*&work_uint; - let inc = BigUint::one(); - - let max = BigUint::from(i+1)*work_uint; - let mut primecache = vec![]; - loop { - number += &inc; - - if prime_utils::is_prime(&number,&primecache) { - primecache.push(number.clone()); - } - if (&number * one_thousand)/&max/ten == &number/&max*one_hundred { - let tried_getting = SystemTime::now(); - let mut new_primecache = arcclone.lock().unwrap(); - if SystemTime::now().duration_since(tried_getting).unwrap().as_millis() > 50 { - eprintln!("[WARN] Waited 0.05+ seconds for lock!"); + thread::scope(|scope| { + for i in 0..THREADS { + let arcclone = primearc.clone(); + scope.spawn(move || { + try_set_thread_priority(); + + let one_thousand = &BigUint::from(SPLITTER * 10); + let one_hundred = &BigUint::from(SPLITTER); + let ten = &BigUint::from(10u8); + + let work_uint = BigUint::from(workloads); + let mut number = BigUint::from(i) * &work_uint; + static INC: once_cell::sync::Lazy = Lazy::new(BigUint::one); + + let max = BigUint::from(i + 1) * work_uint; + let mut primecache = Vec::with_capacity(NU); + let mut primecache_outside_len = 0; + loop { + number += &*INC; + + if prime_utils::is_prime(&number, &primecache) { + primecache.push(number.clone()); + progress.fetch_add(1, std::sync::atomic::Ordering::Relaxed); } - new_primecache.append(&mut primecache); - new_primecache.sort(); - new_primecache.dedup(); - - primecache = new_primecache.clone(); - - } - if number == max { - break; - } - } + if (&number * one_thousand) / &max / ten == &number / &max * one_hundred { + let tried_getting = SystemTime::now(); + let mut new_primecache = arcclone.lock().unwrap(); + if SystemTime::now() + .duration_since(tried_getting) + .unwrap() + .as_millis() + > 50 + { + eprintln!("[WARN] Waited 0.05+ seconds for lock!"); + } - let mut new_primecache = arcclone.lock().unwrap(); - new_primecache.append(&mut primecache); - new_primecache.sort(); - new_primecache.dedup(); - }); - joins.push(handle); - } + new_primecache.extend_from_slice(&primecache[primecache_outside_len..]); + new_primecache.sort_unstable(); - for handle in joins { - handle.join().unwrap(); - } + primecache.clone_from(&new_primecache); + primecache_outside_len = new_primecache.len(); + } + if number == max { + break; + } + } + + let mut new_primecache = arcclone.lock().unwrap(); + new_primecache.extend_from_slice(&primecache[primecache_outside_len..]); + new_primecache.sort_unstable(); + + threads_done.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + }); + } + + loop { + let n = progress.load(std::sync::atomic::Ordering::Relaxed); + let threads_completed = threads_done.load(std::sync::atomic::Ordering::Relaxed); + + println!( + "Progress: {}/{} ({:.0}%) | {}", + n, + N, + n as f64 / NF * 100.0, + threads_completed + ); + std::thread::sleep(std::time::Duration::from_millis(500)); + + if threads_completed == THREADS { + break; + } + } + }); let mut primes = primearc.lock().unwrap().to_vec(); - let removed:i32 = if primes.len() > NU { + let removed: i32 = if primes.len() > NU { let mut rem = 0; loop { if primes.len() <= NU { break; } - rem+=1; + rem += 1; primes.pop(); } rem @@ -159,13 +176,13 @@ fn main() { 0 }; - let added = NU-primes.len(); + let added = NU - primes.len(); if primes.len() < NU { println!("[INFO] less primes than expected"); - let mut number = BigUint::from(THREADS)*BigUint::from(workloads); - let inc = BigUint::one(); + let mut number = BigUint::from(THREADS) * BigUint::from(workloads); + static INC: once_cell::sync::Lazy = Lazy::new(BigUint::one); loop { - number += &inc; + number += &*INC; if prime_utils::is_prime(&number, &primes) { primes.push(number.clone()); } @@ -176,17 +193,18 @@ fn main() { } let new_sys_time = SystemTime::now(); - let difference = new_sys_time.duration_since(sys_time) - .expect("Clock may have gone backwards"); + let difference = new_sys_time + .duration_since(sys_time) + .expect("Clock may have gone backwards"); - assert_eq!(primes.len(),NU); + assert_eq!(primes.len(), NU); - println!("primes added: {added} | % added: {}% | removed: {removed}",to_f64(added)/to_f64(primes.len())*100.0); + println!( + "primes added: {added} | % added: {}% | removed: {removed}", + to_f64(added) / to_f64(primes.len()) * 100.0 + ); println!("time: {difference:?}"); println!("writing primes..."); write_primes(&primes); - - - } diff --git a/src/primality_test.rs b/src/primality_test.rs index 5c70f5c..13df6ee 100644 --- a/src/primality_test.rs +++ b/src/primality_test.rs @@ -10,7 +10,6 @@ pub mod primality_tests { BigUint::from_bytes_be(&buf) } - pub fn is_probably_prime(number: &BigUint, iterations: u32) -> bool { if number <= &BigUint::one() || number == &BigUint::from(4u32) { return false; @@ -23,7 +22,7 @@ pub mod primality_tests { d /= 2u32; } for _ in 0..iterations { - let a = generate_random_biguint((number.bits()-1) as usize); + let a = generate_random_biguint((number.bits() - 1) as usize); let mut x = mod_exp(a.clone(), &d, number); if x == one || x == number - &one { continue; @@ -42,7 +41,7 @@ pub mod primality_tests { } true } - + fn mod_exp(mut base: BigUint, ex: &BigUint, modulus: &BigUint) -> BigUint { let mut exp = ex.clone(); let mut result = BigUint::one(); @@ -56,5 +55,4 @@ pub mod primality_tests { } result } - }