diff --git a/Cargo.lock b/Cargo.lock index 52c80f3..b2a75c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,11 +14,24 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "isprime" version = "0.1.0" dependencies = [ + "num", "num-bigint", + "rand", "thread-priority", ] @@ -37,6 +50,20 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -48,6 +75,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +dependencies = [ + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -58,6 +94,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -68,17 +127,66 @@ dependencies = [ ] [[package]] -name = "thread-priority" -version = "0.10.0" +name = "ppv-lite86" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978519ae4c6891352f964b88da4ab5a3a9b74a40247cda5baee145dae6cd3b71" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rustversion" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" + +[[package]] +name = "thread-priority" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee4429f2c3bbeafa7136ea54d75a5f38b02e4f006c0b310f07e35c3b49eb3e7" dependencies = [ "cfg-if", "libc", "log", + "rustversion", "winapi", ] +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 007a68e..600baaf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -num-bigint = { default-features = false, version = "0" } -thread-priority = "0" +num = "0.4.0" +thread-priority = "0.12.0" +rand = "0.8.5" +num-bigint= { default-features = false, version = "0.4.3" } [profile.release] lto = true # Enable link-time optimization diff --git a/optimize_dependencies.bat b/optimize_dependencies.bat new file mode 100644 index 0000000..25fb54b --- /dev/null +++ b/optimize_dependencies.bat @@ -0,0 +1,2 @@ +REM This uses cargo-unused-features +unused-features analyze && unused-features prune --input report.json \ No newline at end of file diff --git a/src/is_prime.rs b/src/is_prime.rs index 6658f0d..632f3e0 100644 --- a/src/is_prime.rs +++ b/src/is_prime.rs @@ -1,13 +1,15 @@ pub mod prime_utils { - use num_bigint::BigUint; + use num::{BigUint, One, Zero}; - pub fn log_2(x: BigUint) -> u64 { + use crate::primality_test::primality_tests::is_probably_prime; + + #[must_use] pub fn log_2(x: &BigUint) -> u64 { x.bits() - 1 } - 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; } @@ -23,11 +25,11 @@ pub mod prime_utils { // number = 2^a - 1 // a = log2(number + 1) - let a = log_2(number+1u8); - if BigUint::from(2u8).pow(a as u32)-BigUint::from(1u8) != *number { - let mut i = BigUint::from(1u8); - let one = BigUint::from(1u8); - let zero = BigUint::from(0u8); + 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 @@ -41,6 +43,10 @@ pub mod prime_utils { } } + if !is_probably_prime(number,5) { + return false; + } + loop { i += &one; if number%&i == zero { @@ -50,6 +56,8 @@ pub mod prime_utils { return true; } } + + } // 4 12 194 diff --git a/src/main.rs b/src/main.rs index ccbc32d..001e1eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,12 @@ -#![warn(clippy::pedantic)] +#![warn(clippy::perf)] +#![warn(clippy::all)] + pub mod is_prime; +pub mod primality_test; use std::{time::SystemTime,thread, io::Write}; -use num_bigint::BigUint; +use num::{BigUint, One}; use crate::is_prime::prime_utils; use thread_priority::{set_current_thread_priority,ThreadPriority}; @@ -20,14 +23,40 @@ fn p(n: f64) -> f64 { ) } - -fn main() { - - if set_current_thread_priority(ThreadPriority::Max).is_err() { - eprintln!("failed to set thread priority to max"); +fn to_usize(f:f64) -> usize { + let rounded_num: i64 = f.round() as i64; + if rounded_num >= 0 { + rounded_num as usize + } else { + 0 } +} - /* +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() { + eprintln!("[WARN] failed to set thread priority to max"); + } +} + +fn write_primes(primes: &[BigUint]) { + let mut file = std::fs::File::create("primes.json").unwrap(); + file.write_all(b"[").unwrap(); + let mut it = primes.iter().peekable(); + while let Some(prime) = it.next() { + file.write_all(prime.to_string().as_bytes()).unwrap(); + if it.peek().is_some() { + file.write_all(b",").unwrap(); + } + } + file.write_all(b"]").unwrap(); +} + + +/* let mut buffer = String::new(); let stdin = io::stdin(); print!("please enter the number to check: "); @@ -43,14 +72,19 @@ fn main() { println!("\n{number} is not a prime"); } */ +fn main() { + const N:i64 = 100_000; + const NU:usize = N as usize; + const THREADS: usize = 12; + const SPLITTER: u128 = 10000u128; + + try_set_thread_priority(); let sys_time = SystemTime::now(); - const N:i64 = 100_000; - const NU:usize = N as usize; let nf:f64 = 100_000f64; - let nthprime_approx:usize = p(nf*1.02).ceil() as usize; - const THREADS: usize = 12; + let nthprime_approx:usize = to_usize(p(nf*1.02)); + let workloads = nthprime_approx/THREADS; let primecache: Vec = vec![]; @@ -61,20 +95,15 @@ fn main() { let arcclone = primearc.clone(); let handle = thread::spawn(move || { - if set_current_thread_priority(ThreadPriority::Max).is_err() { - eprintln!("failed to set thread priority to max"); - } + try_set_thread_priority(); - const SPLITTER: u128 = 10000u128; 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; - let inc = BigUint::from(1u8); - // let zero = BigUint::from(0u8); + let inc = BigUint::one(); let max = BigUint::from(i+1)*work_uint; let mut primecache = vec![]; @@ -83,13 +112,12 @@ fn main() { if prime_utils::is_prime(&number,&primecache) { primecache.push(number.clone()); - //println!("Found a prime {} {}",number, primecache.len()); } 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!("Waited 0.05+ seconds for lock!"); + eprintln!("[WARN] Waited 0.05+ seconds for lock!"); } new_primecache.append(&mut primecache); new_primecache.sort(); @@ -133,9 +161,9 @@ fn main() { let added = NU-primes.len(); if primes.len() < NU { - println!("Less primes than expected!"); + println!("[INFO] less primes than expected"); let mut number = BigUint::from(THREADS)*BigUint::from(workloads); - let inc = BigUint::from(1u8); + let inc = BigUint::one(); loop { number += &inc; if prime_utils::is_prime(&number, &primes) { @@ -153,22 +181,11 @@ fn main() { assert_eq!(primes.len(),NU); - println!("primes added: {} | % added: {}% | removed: {}",added,(added as f64)/primes.len() as f64*100.0,removed); - + println!("primes added: {added} | % added: {}% | removed: {removed}",to_f64(added)/to_f64(primes.len())*100.0); println!("time: {difference:?}"); - println!("writing primes..."); - let mut file = std::fs::File::create("primes.json").unwrap(); - file.write_all(b"[").unwrap(); - let mut it = primes.iter().peekable(); - while let Some(prime) = it.next() { - file.write_all(prime.to_string().as_bytes()).unwrap(); - if it.peek().is_some() { - file.write_all(b",").unwrap(); - } - } - file.write_all(b"]").unwrap(); + write_primes(&primes); diff --git a/src/primality_test.rs b/src/primality_test.rs new file mode 100644 index 0000000..5c70f5c --- /dev/null +++ b/src/primality_test.rs @@ -0,0 +1,60 @@ +pub mod primality_tests { + use num::{BigUint, Integer, One, Zero}; + use rand::RngCore; + + fn generate_random_biguint(num_bits: usize) -> BigUint { + let mut rng = rand::thread_rng(); + let bytes = num_bits / 8 + 1; + let mut buf = vec![0u8; bytes]; + rng.fill_bytes(&mut buf); + 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; + } else if number <= &BigUint::from(3u32) { + return true; + } + let one = BigUint::one(); + let mut d = number - &one; + while d.is_even() { + d /= 2u32; + } + for _ in 0..iterations { + 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; + } + let mut continue_loop = false; + for _ in 0..(number.bits() - 1) { + x = mod_exp(x.clone(), &BigUint::from(2u32), number); + if x == number - &one { + continue_loop = true; + break; + } + } + if !continue_loop { + return false; + } + } + true + } + + fn mod_exp(mut base: BigUint, ex: &BigUint, modulus: &BigUint) -> BigUint { + let mut exp = ex.clone(); + let mut result = BigUint::one(); + base %= modulus; + while !exp.is_zero() { + if exp.is_odd() { + result = (&result * &base) % modulus; + } + base = base.pow(2) % modulus; + exp /= 2u32; + } + result + } + +}