Compare commits

..

12 Commits

Author SHA1 Message Date
90069e9ab4 refactor code 2024-07-23 01:36:30 +02:00
f6200bc99a remove unused code; refactor code 2024-07-19 18:10:51 +02:00
36fc8cf5c5 refactor code
back to mutex as we no longer have read-only situations
2024-07-19 18:06:38 +02:00
0fe3ffaa59 speed up prime calculations by 50%
add tool to check a prime as cmd arg
2024-07-19 17:15:18 +02:00
49e24e5a61 handle primes as strings to allow for very large primes 2024-07-19 17:14:15 +02:00
39cc138252 refactor a bit 2024-07-18 21:45:02 +02:00
2af65c41f0 refactor/clean a bit 2024-07-18 15:52:58 +02:00
f125145690 get rid of to_f64
reason: faulty and unneeded
2024-07-18 15:45:27 +02:00
55ffd09fe5 make some statics actually static 2024-07-17 01:00:15 +02:00
ce507071b9 big performance uplift 2024-07-17 00:56:13 +02:00
099012a60b Fix prime calculator; more threads by default 2024-07-11 03:08:38 +02:00
71138258e6 clean up code a bit
also reformat
2024-07-11 02:37:44 +02:00
9 changed files with 410 additions and 292 deletions

6
.gitignore vendored
View File

@ -1,3 +1,9 @@
/target /target
report.json report.json
primes.json primes.json
primes*.json
primes*.txt
primes*.zip
dhat*
flamegraph*
perf*

154
Cargo.lock generated
View File

@ -4,9 +4,15 @@ version = 3
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -16,9 +22,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.8" version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@ -31,30 +37,35 @@ version = "0.1.0"
dependencies = [ dependencies = [
"num", "num",
"num-bigint", "num-bigint",
"once_cell",
"rand", "rand",
"serde_json",
"thread-priority", "thread-priority",
] ]
[[package]] [[package]]
name = "libc" name = "itoa"
version = "0.2.139" version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "libc"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.17" version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "num" name = "num"
version = "0.4.0" version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"num-complex", "num-complex",
@ -66,39 +77,38 @@ dependencies = [
[[package]] [[package]]
name = "num-bigint" name = "num-bigint"
version = "0.4.3" version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [ dependencies = [
"autocfg",
"num-integer", "num-integer",
"num-traits", "num-traits",
"serde",
] ]
[[package]] [[package]]
name = "num-complex" name = "num-complex"
version = "0.4.3" version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
dependencies = [ dependencies = [
"num-traits", "num-traits",
] ]
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.45" version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [ dependencies = [
"autocfg",
"num-traits", "num-traits",
] ]
[[package]] [[package]]
name = "num-iter" name = "num-iter"
version = "0.1.43" version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"num-integer", "num-integer",
@ -107,11 +117,10 @@ dependencies = [
[[package]] [[package]]
name = "num-rational" name = "num-rational"
version = "0.4.1" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [ dependencies = [
"autocfg",
"num-bigint", "num-bigint",
"num-integer", "num-integer",
"num-traits", "num-traits",
@ -119,19 +128,43 @@ dependencies = [
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.15" version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.17" version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.8.5" version = "0.8.5"
@ -164,16 +197,65 @@ dependencies = [
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.11" version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "serde"
version = "1.0.204"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.204"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "2.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "thread-priority" name = "thread-priority"
version = "0.12.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ee4429f2c3bbeafa7136ea54d75a5f38b02e4f006c0b310f07e35c3b49eb3e7" checksum = "0d3b04d33c9633b8662b167b847c7ab521f83d1ae20f2321b65b5b925e532e36"
dependencies = [ dependencies = [
"bitflags",
"cfg-if", "cfg-if",
"libc", "libc",
"log", "log",
@ -181,6 +263,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"

View File

@ -2,17 +2,48 @@
name = "isprime" name = "isprime"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
default-run = "isprime"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
num = "0.4.0" num = "0.4"
thread-priority = "0.12.0" rand = "0.8"
rand = "0.8.5" num-bigint = { default-features = false, version = "0.4", features = ["serde"] }
num-bigint= { default-features = false, version = "0.4.3" } once_cell = "1.19"
serde_json = "1.0"
[target.'cfg(windows)'.dependencies]
thread-priority = "1.1"
[profile.release] [profile.release]
lto = true # Enable link-time optimization lto = true # Enable link-time optimization
codegen-units = 1 # Reduce number of codegen units to increase optimizations codegen-units = 1 # Reduce number of codegen units to increase optimizations
panic = 'abort' # Abort on panic panic = 'abort' # Abort on panic
strip = true # Strip symbols from binary; remove pdb # strip = true # Strip symbols from binary; remove pdb
overflow-checks = false
debug = true
[profile.dev]
opt-level = 3
[lints.clippy]
pedantic = { level = "deny", priority = -1 }
perf = { level = "deny", priority = 1 }
complexity = { level = "deny", priority = -1 }
style = { level = "deny", priority = -1 }
correctness = { level = "deny", priority = -1 }
format_collect = "deny"
format_in_format_args = "deny"
format_push_string = "deny"
mut_mut = "deny"
let_underscore_untyped = "deny"
str_to_string = "deny"
cast_possible_truncation = "allow"
cast_precision_loss = "allow"
cast_sign_loss = "allow"
missing_errors_doc = "allow"
[[bin]]
name = "isprime"

26
check_primes.js Normal file
View File

@ -0,0 +1,26 @@
const assert = require("assert");
const primes_generated = require("./primes.json");
const correct_primes = require("./primes1.json");
assert(
primes_generated.length == correct_primes.length,
"Number of primes generated is not equal to the number of correct primes",
);
for (let i = 0; i < primes_generated.length; i++) {
if (primes_generated[i] !== correct_primes[i]) {
let bigger_smaller = "="
if (primes_generated[i] > correct_primes[i]) { bigger_smaller = ">" } else if (primes_generated[i] < correct_primes[i]) { "<" }
console.error(
`Incorrect prime at index ${i}: ${primes_generated[i]}(gen) | ${correct_primes[i]}(list) | gen is ${bigger_smaller}`,
);
process.exit(1);
}
}
console.log("All primes are correct");
console.log(
"Last prime in generated primes: ",
primes_generated[primes_generated.length - 1],
);

28
convert_primelist.py Normal file
View File

@ -0,0 +1,28 @@
import json
def convert_primes_to_json(file_path):
# Step 1: Read the file content
with open(file_path, 'r') as file:
lines = file.readlines()
primes = []
for line in lines:
# Step 2: Extract prime numbers
# Split each line into words and filter out non-numeric entries
numbers = [num for num in line.split() if num.isdigit()]
primes.extend(numbers)
# Step 3: Convert the list of primes to a JSON array
primes_json = json.dumps(primes, indent=4)
return primes_json
# Example usage:
file_path = 'primes1.txt'
primes_json = convert_primes_to_json(file_path)
print(primes_json)
# If you want to save the JSON array to a file:
output_path = 'primes1.json'
with open(output_path, 'w') as output_file:
output_file.write(primes_json)

View File

@ -1,6 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
]
}

View File

@ -1,73 +1,76 @@
pub mod prime_utils { pub mod prime_utils {
use num::{BigUint, One, Zero}; use num::{BigUint, One};
use once_cell::sync::Lazy;
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 x.bits() - 1
} }
#[must_use] pub fn is_prime(number: &BigUint, g_primes: &Vec<BigUint>) -> bool { static FOUR: Lazy<BigUint> = Lazy::new(|| BigUint::from(4u8));
if BigUint::from(1u8) == *number { static TWO: Lazy<BigUint> = Lazy::new(|| BigUint::from(2u8));
static ONE: Lazy<BigUint> = Lazy::new(BigUint::one);
const ZERO: BigUint = BigUint::ZERO;
#[must_use]
pub fn is_prime(number: &BigUint) -> bool {
if &*ONE >= number {
return false; return false;
} }
if BigUint::from(4u8) > *number { if &*FOUR > number {
return true; return true;
} }
if !number.bit(0) {
if number.sqrt().pow(2) == *number {
return false; return false;
} }
let two = BigUint::from(2u8); // mersenne numbers = 2^a - 1
// number = 2^a - 1
// a = log2(number + 1) // a = log2(number + 1)
let a = log_2(&(number+1u8)); let a = log_2(&(number + 1u8));
if BigUint::from(2u8).pow(a as u32)-BigUint::one() != *number {
let is_mersenne = {
let num_p2 = {
let mut num = BigUint::default();
num.set_bit(a, true);
num
};
assert!(num_p2 > BigUint::one());
let num_p2 = num_p2 - &*ONE;
&num_p2 == number
};
if is_mersenne {
return mersenne_check(number, a);
}
let sqrtnum = number.sqrt() + &*ONE; //fake ceil function
inner_prime(number, &sqrtnum)
}
fn mersenne_check(number: &BigUint, a: u64) -> bool {
let mut last = FOUR.clone();
for _ in 2..a {
last = (last.pow(2) - &*TWO) % number;
}
last == ZERO
}
fn inner_prime(number: &BigUint, sqrtnum: &BigUint) -> bool {
let mut i = BigUint::one(); 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;
}
}
}
}
if !is_probably_prime(number,5) {
return false;
}
loop { loop {
i += &one; i += &*TWO; //we begin checking 3 and then continue with every second number as every even number is divisible by 2 and we already checked that
if number%&i == zero { if &i >= sqrtnum {
return false;
}
if i == sqrtnum {
return true; return true;
} }
if number % &i == ZERO {
return false;
} }
} }
// 4 12 194
let mut last = BigUint::from(4u8);
for _i in 2..a {
last = (last.pow(2)-&two)%number;
}
last == BigUint::from(0u8)
} }
} }

View File

@ -1,29 +1,32 @@
#![warn(clippy::perf)] #![warn(clippy::perf)]
#![warn(clippy::all)] #![warn(clippy::all)]
mod is_prime;
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 crate::is_prime::prime_utils;
use thread_priority::{set_current_thread_priority,ThreadPriority}; use num::{BigUint, One};
use std::{
env::args,
io::Write,
sync::{
atomic::{AtomicU64, AtomicUsize},
Arc, Mutex,
},
thread,
time::{Instant, SystemTime},
};
fn p(n: f64) -> f64 { fn p(n: f64) -> f64 {
let ln_n = n.ln(); let ln_n = n.ln();
let ln_ln_n = ln_n.ln(); let ln_ln_n = ln_n.ln();
let ln_ln_ln_n = ln_ln_n.ln(); let ln_ln_ln_n = ln_ln_n.ln();
n * ( n * (ln_n + ln_ln_n - 1.0 + (ln_ln_ln_n - 2.0) / ln_n
ln_n + ln_ln_n - 1.0 - ((ln_ln_n).powi(2) - 6.0 * ln_ln_n + 11.0) / (2.0 * ln_n)
+ (ln_ln_ln_n - 2.0) / ln_n + ((ln_ln_n / ln_n).powi(3)) * (1.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)
)
} }
fn to_usize(f:f64) -> usize { fn to_usize(f: f64) -> usize {
let rounded_num: i64 = f.round() as i64; let rounded_num: i64 = f.round() as i64;
if rounded_num >= 0 { if rounded_num >= 0 {
rounded_num as usize rounded_num as usize
@ -32,161 +35,160 @@ fn to_usize(f:f64) -> usize {
} }
} }
fn to_f64(u:usize) -> f64 { #[cfg(target_os = "windows")]
f64::from_bits(u as u64)
}
fn try_set_thread_priority() { fn try_set_thread_priority() {
if set_current_thread_priority(ThreadPriority::Max).is_err() { use thread_priority::{set_current_thread_priority, ThreadPriority};
if let Err(e) = set_current_thread_priority(ThreadPriority::Max) {
eprintln!("[WARN] failed to set thread priority to max"); eprintln!("[WARN] failed to set thread priority to max");
eprintln!("{e}");
} }
} }
fn write_primes(primes: &[BigUint]) { fn write_primes(primes: &[BigUint]) {
let primes: Vec<String> = primes
.iter()
.map(std::string::ToString::to_string)
.collect();
let mut file = std::fs::File::create("primes.json").unwrap(); let mut file = std::fs::File::create("primes.json").unwrap();
file.write_all(b"[").unwrap(); file.write_all(serde_json::to_string(&primes).unwrap().as_bytes())
let mut it = primes.iter().peekable(); .unwrap();
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();
} }
const N: i64 = 1_000_000;
const NF: f64 = N as f64;
const NU: usize = N as usize;
const THREADS: usize = 30;
/* fn worker(
let mut buffer = String::new(); workloads: usize,
let stdin = io::stdin(); i: usize,
print!("please enter the number to check: "); progress: &AtomicU64,
io::stdout().flush().expect("could not flush"); arcclone: &Arc<Mutex<Vec<BigUint>>>,
stdin.read_line(&mut buffer).expect("could not read from stdin"); threads_done: &AtomicUsize,
buffer = buffer.trim().to_owned(); ) {
#[cfg(target_os = "windows")]
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 THREADS: usize = 12;
const SPLITTER: u128 = 10000u128;
try_set_thread_priority(); 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 primecache: Vec<BigUint> = vec![];
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 one_thousand = &BigUint::from(SPLITTER*10);
let one_hundred = &BigUint::from(SPLITTER);
let ten = &BigUint::from(10u8);
let work_uint = BigUint::from(workloads); let work_uint = BigUint::from(workloads);
let mut number = BigUint::from(i)*&work_uint; let mut number = BigUint::from(i) * &work_uint;
let inc = BigUint::one();
let max = BigUint::from(i+1)*work_uint; let max = BigUint::from(i + 1) * work_uint;
let mut primecache = vec![]; let mut primecache = Vec::with_capacity(NU);
loop { loop {
number += &inc; number += &BigUint::one();
if prime_utils::is_prime(&number,&primecache) { if prime_utils::is_prime(&number) {
primecache.push(number.clone()); primecache.push(number.clone());
} progress.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
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!");
}
new_primecache.append(&mut primecache);
new_primecache.sort();
new_primecache.dedup();
primecache = new_primecache.clone();
} }
if number == max { if number == max {
break; break;
} }
} }
let mut new_primecache = arcclone.lock().unwrap(); arcclone.lock().unwrap().append(&mut primecache);
new_primecache.append(&mut primecache);
new_primecache.sort(); threads_done.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
new_primecache.dedup(); }
});
joins.push(handle); fn main() {
if let Some(prime) = args().nth(1) {
use std::str::FromStr;
let prime = BigUint::from_str(&prime).unwrap();
let is_prime = is_prime::prime_utils::is_prime(&prime);
println!("Number is {}a prime", if is_prime { "" } else { "not " });
return;
} }
for handle in joins { let sys_time = SystemTime::now();
handle.join().unwrap();
let nthprime_approx: usize = to_usize(p(NF * 1.02));
let workloads = nthprime_approx / THREADS;
let primecache: Vec<BigUint> = Vec::with_capacity(NU);
let primemutex = std::sync::Mutex::new(primecache);
let primearc = std::sync::Arc::new(primemutex);
let progress_val = AtomicU64::new(0);
let progress = &progress_val;
let threads_done_val = AtomicUsize::new(0);
let threads_done = &threads_done_val;
thread::scope(|scope| {
for i in 0..THREADS {
let arcclone = primearc.clone();
scope.spawn(move || worker(workloads, i, progress, &arcclone, threads_done));
} }
let mut primes = primearc.lock().unwrap().to_vec(); let mut last_progress = Instant::now();
let removed:i32 = if primes.len() > NU {
let mut rem = 0;
loop { loop {
if primes.len() <= NU { let threads_completed = threads_done.load(std::sync::atomic::Ordering::Relaxed);
if threads_completed == THREADS {
break; break;
} }
rem+=1;
primes.pop();
}
rem
} else {
0
};
let added = NU-primes.len(); if last_progress.elapsed().as_millis() >= 500 {
last_progress = Instant::now();
let n = progress.load(std::sync::atomic::Ordering::Relaxed);
println!(
"Progress: {:0>width$}/{} ({:>3}%) | {:0>t_width$}",
n,
N,
(n as f64 / NF * 100.0).min(100.0).floor(),
threads_completed,
width = N.to_string().len(),
t_width = THREADS.to_string().len()
);
}
std::thread::sleep(std::time::Duration::from_millis(100));
}
});
let mut primes = primearc.lock().unwrap();
primes.sort_unstable();
let removed = primes.len() - NU;
primes.truncate(NU);
let added = NU - primes.len();
if primes.len() < NU { if primes.len() < NU {
let inc = BigUint::from(2u8);
println!("[INFO] less primes than expected"); println!("[INFO] less primes than expected");
let mut number = BigUint::from(THREADS)*BigUint::from(workloads); let mut number = BigUint::from(THREADS) * BigUint::from(workloads);
let inc = BigUint::one(); if &number % &inc == BigUint::ZERO {
number += BigUint::one();
}
loop { loop {
number += &inc; number += &inc;
if prime_utils::is_prime(&number, &primes) { if prime_utils::is_prime(&number) {
primes.push(number.clone()); primes.push(number.clone());
}
if primes.len() == NU { if primes.len() == NU {
break; break;
} }
} }
} }
}
let new_sys_time = SystemTime::now(); let difference = sys_time.elapsed().unwrap();
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} | removed: {removed}");
println!("time: {difference:?}"); println!("time: {difference:?}");
println!("writing primes..."); println!("writing primes...");
write_primes(&primes); write_primes(&primes);
} }

View File

@ -1,60 +0,0 @@
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
}
}