Compare commits

...

10 Commits

5 changed files with 165 additions and 55 deletions

115
Cargo.lock generated
View File

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3
[[package]] [[package]]
name = "ansi_term" name = "ansi_term"
version = "0.11.0" version = "0.11.0"
@ -20,12 +22,24 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.2.1" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "2.33.3" version = "2.33.3"
@ -41,6 +55,56 @@ dependencies = [
"vec_map", "vec_map",
] ]
[[package]]
name = "crossbeam-channel"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9"
dependencies = [
"cfg-if",
"crossbeam-utils",
"lazy_static",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6"
dependencies = [
"cfg-if",
"lazy_static",
]
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.3.2" version = "0.3.2"
@ -63,6 +127,7 @@ dependencies = [
name = "indivisible" name = "indivisible"
version = "2.0.0" version = "2.0.0"
dependencies = [ dependencies = [
"rayon",
"structopt", "structopt",
] ]
@ -78,6 +143,25 @@ version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213" checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213"
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
dependencies = [
"hermit-abi",
"libc",
]
[[package]] [[package]]
name = "proc-macro-error" name = "proc-macro-error"
version = "1.0.4" version = "1.0.4"
@ -120,6 +204,37 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rayon"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
dependencies = [
"autocfg",
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"lazy_static",
"num_cpus",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.8.0" version = "0.8.0"

View File

@ -12,3 +12,4 @@ keywords = ["primes", "math"]
[dependencies] [dependencies]
structopt = "0.3.13" structopt = "0.3.13"
rayon = "1.5"

View File

@ -1,10 +1,9 @@
=================== # Indivisible
*** Indivisible ***
===================
Indivisible is an optimized prime number generator and tester written in Rust. Indivisible is an optimized prime number generator and tester written in Rust.
# Build & Installation ## Build & Installation
----------------------
To build the project you will require the Rust compiler and build To build the project you will require the Rust compiler and build
system, `cargo`. At which point you simply run `cargo build` in the root system, `cargo`. At which point you simply run `cargo build` in the root
directory of the project. To create an optimized release build append directory of the project. To create an optimized release build append
@ -15,8 +14,8 @@ the manpage documentation by running the `install` script. In a similar
manner, you can run the `uninstall` script to remove the previously manner, you can run the `uninstall` script to remove the previously
installed binary and documentation. installed binary and documentation.
# Usage ## Usage
-------
The purpose of Indivisible is to find the nth prime and all the primes The purpose of Indivisible is to find the nth prime and all the primes
before it. The basic usage is `indivisible <n>` where `n` is the ordinal before it. The basic usage is `indivisible <n>` where `n` is the ordinal
of the prime you'd like to find. To display all primes before `n`, you of the prime you'd like to find. To display all primes before `n`, you
@ -27,22 +26,23 @@ can also import prime numbers previously computed with the `--import` or
`-i` option. To store already computed primes you are expected to use `-i` option. To store already computed primes you are expected to use
piping like any UNIX user would expect. Here is an example: piping like any UNIX user would expect. Here is an example:
# store first 100 primes in ./primes ```bash
indivisible -v 100 > ./primes # store first 100 primes in ./primes
# appends next 400 primes indivisible -v 100 > ./primes
indivisible -i ./primes -v 500 >> ./primes # appends next 400 primes
# display the 600th prime indivisible -i ./primes -v 500 >> ./primes
indivisible -i ./primes 600 # display the 600th prime
indivisible -i ./primes 600
```
# Legacy ## Legacy
--------
This project was originally written in C. It can be found on my GitLab This project was originally written in C. It can be found in the
page.[1] [indivisible-legacy repository](https://gitlab.com/naortega/Indivisible-legacy)
on my GitLab.
## License
# License
---------
This project is licensed under the terms & conditions of the GNU General This project is licensed under the terms & conditions of the GNU General
Public License version 3 or greater (see `LICENSE` file for more Public License version 3 or greater (see `LICENSE` file for more
information). information).
[1] https://gitlab.com/naortega/Indivisible-legacy

View File

@ -30,12 +30,12 @@ struct Opt
{ {
#[structopt(short, long, help = "Print all found primes")] #[structopt(short, long, help = "Print all found primes")]
verbose:bool, verbose:bool,
#[structopt(short, long, name="FILE", help = "Import prime numbers from FILE")] #[structopt(short, long, name = "FILE", help = "Import prime numbers from FILE")]
import:Option<PathBuf>, import:Option<PathBuf>,
#[structopt(short, long, help = "Test if n is prime instead of generation")] #[structopt(short, long, help = "Test if n is prime instead of generation")]
test:bool, test:bool,
#[structopt(help = "Ordinal of the prime to generate")] #[structopt(help = "Ordinal of the prime to generate")]
n:usize, n:u64,
} }
fn main() fn main()
@ -50,12 +50,9 @@ fn main()
{ {
let in_file = File::open(opts.import.unwrap()).unwrap(); let in_file = File::open(opts.import.unwrap()).unwrap();
let reader = BufReader::new(in_file); let reader = BufReader::new(in_file);
for line in reader.lines() reader.lines().into_iter().for_each(|x| {
{ primes.push_back(x.unwrap().parse().unwrap());
let line = line.unwrap(); });
let aux:u64 = line.parse().unwrap();
primes.push_back(aux);
}
} }
if opts.test if opts.test
@ -64,17 +61,17 @@ fn main()
// if no primes were imported, test from beginning (2) // if no primes were imported, test from beginning (2)
if primes.len() == 0 if primes.len() == 0
{ {
res = test::is_prime(n as u64); res = test::is_prime(n);
} }
// `n` should be in `primes` if the last prime is larger than `n` // `n` should be in `primes` if the last prime is larger than `n`
else if primes.back().unwrap() >= &(n as u64) else if primes.back().unwrap() >= &(n)
{ {
res = primes.contains(&(n as u64)); res = primes.contains(&(n));
} }
// we can memory test `n` if the last prime is >= sqrt(n) // we can memory test `n` if the last prime is >= sqrt(n)
else if primes.back().unwrap() >= &((n as f64).sqrt() as u64) else if primes.back().unwrap() >= &((n as f64).sqrt() as u64)
{ {
res = test::is_prime_mem(n as u64, &primes) res = test::is_prime_mem(n, &primes)
} }
/* /*
* if we have less primes than sqrt(n) then we can test all those * if we have less primes than sqrt(n) then we can test all those
@ -83,10 +80,10 @@ fn main()
*/ */
else else
{ {
res = test::is_prime_mem(n as u64, &primes); res = test::is_prime_mem(n, &primes);
if res if res
{ {
res = test::is_prime_f(n as u64, primes.back().unwrap() + 2); res = test::is_prime_f(n, primes.back().unwrap() + 2);
} }
} }
@ -110,9 +107,9 @@ fn main()
else else
{ {
// if `primes` already contains the nth prime, print it // if `primes` already contains the nth prime, print it
if primes.len() >= n if primes.len() >= n as usize
{ {
println!("{}", primes.get(n-1).unwrap()); println!("{}", primes.get((n as usize) - 1).unwrap());
} }
else else
{ {
@ -137,7 +134,7 @@ fn main()
candidate = *primes.back().unwrap() + 2; candidate = *primes.back().unwrap() + 2;
} }
while primes.len() < n while primes.len() < n as usize
{ {
if test::is_prime_mem(candidate, &primes) if test::is_prime_mem(candidate, &primes)
{ {
@ -153,7 +150,7 @@ fn main()
if !opts.verbose if !opts.verbose
{ {
println!("{}", primes.get(n-1).unwrap()); println!("{}", primes.get((n as usize) - 1).unwrap());
} }
} }
} }

View File

@ -17,12 +17,18 @@
*/ */
use std::collections::VecDeque; use std::collections::VecDeque;
use rayon::prelude::*;
pub fn is_prime_f(n:u64, b:u64) -> bool pub fn is_prime_f(n:u64, b:u64) -> bool
{ {
assert_ne!(b, 0); assert_ne!(b, 0);
assert_ne!(b, 1); assert_ne!(b, 1);
if n == 1
{
return false;
}
let mut start = b; let mut start = b;
if start == 2 if start == 2
{ {
@ -42,14 +48,9 @@ pub fn is_prime_f(n:u64, b:u64) -> bool
} }
let limit = (n as f64).sqrt() as u64 + 1; let limit = (n as f64).sqrt() as u64 + 1;
for i in (start..limit).step_by(2) let composite = (start..limit).step_by(2).collect::<Vec<u64>>()
{ .par_iter().any(|x| n % x == 0);
if n % i == 0 return !composite;
{
return false;
}
}
return true;
} }
pub fn is_prime(n:u64) -> bool pub fn is_prime(n:u64) -> bool
@ -60,12 +61,8 @@ pub fn is_prime(n:u64) -> bool
pub fn is_prime_mem(n:u64, primes:&VecDeque<u64>) -> bool pub fn is_prime_mem(n:u64, primes:&VecDeque<u64>) -> bool
{ {
let limit = (n as f64).sqrt() as u64; let limit = (n as f64).sqrt() as u64;
for i in primes.iter().take_while(|x| **x <= limit) let pp = primes.partition_point(|x| *x < limit);
{ //let composite = primes.par_iter().take(pp+1).any(|x| n % *x == 0);
if n % *i == 0 let composite = primes.iter().take(pp+1).any(|x| n % *x == 0);
{ return !composite;
return false;
}
}
return true;
} }