From bd4d6fcac5e7d817c1bddf0ddc89e486c25f6d70 Mon Sep 17 00:00:00 2001 From: nicoo Date: Wed, 24 Jun 2020 13:37:21 +0200 Subject: [PATCH 1/9] factor: Split the CLI and I/O code off the factoring logic --- src/uu/factor/Cargo.toml | 6 ++-- src/uu/factor/src/cli.rs | 63 +++++++++++++++++++++++++++++++++++ src/uu/factor/src/factor.rs | 65 ++++--------------------------------- 3 files changed, 73 insertions(+), 61 deletions(-) create mode 100644 src/uu/factor/src/cli.rs diff --git a/src/uu/factor/Cargo.toml b/src/uu/factor/Cargo.toml index 7589fe1bb..5631a52da 100644 --- a/src/uu/factor/Cargo.toml +++ b/src/uu/factor/Cargo.toml @@ -11,9 +11,6 @@ keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] edition = "2018" -[lib] -path = "src/factor.rs" - [dependencies] rand = "0.5" uucore = { version="0.0.4", package="uucore", git="https://github.com/uutils/uucore.git", branch="canary" } @@ -22,3 +19,6 @@ uucore_procs = { version="0.0.4", package="uucore_procs", git="https://github.co [[bin]] name = "factor" path = "src/main.rs" + +[lib] +path = "src/cli.rs" diff --git a/src/uu/factor/src/cli.rs b/src/uu/factor/src/cli.rs new file mode 100644 index 000000000..628448964 --- /dev/null +++ b/src/uu/factor/src/cli.rs @@ -0,0 +1,63 @@ +// * This file is part of the uutils coreutils package. +// * +// * (c) 2014 T. Jameson Little +// * (c) 2020 nicoo +// * +// * For the full copyright and license information, please view the LICENSE file +// * that was distributed with this source code. + +#[macro_use] +extern crate uucore; + +use std::error::Error; +use std::io::{self, stdin, stdout, BufRead, Write}; + +mod factor; +pub(crate) use factor::*; + +mod miller_rabin; +mod numeric; +mod rho; +mod table; + +static SYNTAX: &str = "[OPTION] [NUMBER]..."; +static SUMMARY: &str = "Print the prime factors of the given number(s). + If none are specified, read from standard input."; +static LONG_HELP: &str = ""; + +fn print_factors_str(num_str: &str, w: &mut impl io::Write) -> Result<(), Box> { + num_str + .parse::() + .map_err(|e| e.into()) + .and_then(|x| writeln!(w, "{}:{}", x, factor(x)).map_err(|e| e.into())) +} + +pub fn uumain(args: impl uucore::Args) -> i32 { + let matches = app!(SYNTAX, SUMMARY, LONG_HELP).parse(args.collect_str()); + let stdout = stdout(); + let mut w = io::BufWriter::new(stdout.lock()); + + if matches.free.is_empty() { + let stdin = stdin(); + + for line in stdin.lock().lines() { + for number in line.unwrap().split_whitespace() { + if let Err(e) = print_factors_str(number, &mut w) { + show_warning!("{}: {}", number, e); + } + } + } + } else { + for number in &matches.free { + if let Err(e) = print_factors_str(number, &mut w) { + show_warning!("{}: {}", number, e); + } + } + } + + if let Err(e) = w.flush() { + show_error!("{}", e); + } + + 0 +} diff --git a/src/uu/factor/src/factor.rs b/src/uu/factor/src/factor.rs index d56488793..f825c03ab 100644 --- a/src/uu/factor/src/factor.rs +++ b/src/uu/factor/src/factor.rs @@ -1,6 +1,5 @@ // * This file is part of the uutils coreutils package. // * -// * (c) 2014 T. Jameson Little // * (c) 2020 nicoo // * // * For the full copyright and license information, please view the LICENSE file @@ -8,48 +7,35 @@ extern crate rand; -#[macro_use] -extern crate uucore; - use std::collections::BTreeMap; -use std::error::Error; use std::fmt; -use std::io::{self, stdin, stdout, BufRead, Write}; use std::ops; -mod miller_rabin; -mod numeric; -mod rho; -mod table; +use crate::{miller_rabin, rho, table}; -static SYNTAX: &str = "[OPTION] [NUMBER]..."; -static SUMMARY: &str = "Print the prime factors of the given number(s). - If none are specified, read from standard input."; -static LONG_HELP: &str = ""; - -struct Factors { +pub struct Factors { f: BTreeMap, } impl Factors { - fn one() -> Factors { + pub fn one() -> Factors { Factors { f: BTreeMap::new() } } - fn prime(p: u64) -> Factors { + pub fn prime(p: u64) -> Factors { debug_assert!(miller_rabin::is_prime(p)); let mut f = Factors::one(); f.push(p); f } - fn add(&mut self, prime: u64, exp: u8) { + pub fn add(&mut self, prime: u64, exp: u8) { debug_assert!(exp > 0); let n = *self.f.get(&prime).unwrap_or(&0); self.f.insert(prime, exp + n); } - fn push(&mut self, prime: u64) { + pub fn push(&mut self, prime: u64) { self.add(prime, 1) } @@ -81,7 +67,7 @@ impl fmt::Display for Factors { } } -fn factor(mut n: u64) -> Factors { +pub fn factor(mut n: u64) -> Factors { let mut factors = Factors::one(); if n < 2 { @@ -109,43 +95,6 @@ fn factor(mut n: u64) -> Factors { factors } -fn print_factors_str(num_str: &str, w: &mut impl io::Write) -> Result<(), Box> { - num_str - .parse::() - .map_err(|e| e.into()) - .and_then(|x| writeln!(w, "{}:{}", x, factor(x)).map_err(|e| e.into())) -} - -pub fn uumain(args: impl uucore::Args) -> i32 { - let matches = app!(SYNTAX, SUMMARY, LONG_HELP).parse(args.collect_str()); - let stdout = stdout(); - let mut w = io::BufWriter::new(stdout.lock()); - - if matches.free.is_empty() { - let stdin = stdin(); - - for line in stdin.lock().lines() { - for number in line.unwrap().split_whitespace() { - if let Err(e) = print_factors_str(number, &mut w) { - show_warning!("{}: {}", number, e); - } - } - } - } else { - for number in &matches.free { - if let Err(e) = print_factors_str(number, &mut w) { - show_warning!("{}: {}", number, e); - } - } - } - - if let Err(e) = w.flush() { - show_error!("{}", e); - } - - 0 -} - #[cfg(test)] mod tests { use super::factor; From 6713d2ad627fdc2e4e828c47bb8e5a8b55c6337b Mon Sep 17 00:00:00 2001 From: nicoo Date: Thu, 25 Jun 2020 03:38:23 +0200 Subject: [PATCH 2/9] factor: Move recursive factoring logic from rho to factor No functional change, but prepares a coming optimisation. --- src/uu/factor/src/factor.rs | 34 ++++++++++++++++++++++++++++++++-- src/uu/factor/src/rho.rs | 34 +--------------------------------- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/src/uu/factor/src/factor.rs b/src/uu/factor/src/factor.rs index f825c03ab..f77792a58 100644 --- a/src/uu/factor/src/factor.rs +++ b/src/uu/factor/src/factor.rs @@ -11,6 +11,7 @@ use std::collections::BTreeMap; use std::fmt; use std::ops; +use crate::numeric::{Arithmetic, Montgomery}; use crate::{miller_rabin, rho, table}; pub struct Factors { @@ -67,6 +68,33 @@ impl fmt::Display for Factors { } } +fn _factor(num: u64) -> Factors { + use miller_rabin::Result::*; + // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small. + let _factor = |n| { + // TODO: Optimise with 32 and 64b versions + _factor::(n) + }; + + if num == 1 { + return Factors::one(); + } + + let n = A::new(num); + let divisor = match miller_rabin::test::(n) { + Prime => { + return Factors::prime(num); + } + + Composite(d) => d, + Pseudoprime => rho::find_divisor::(n), + }; + + let mut factors = _factor(divisor); + factors *= _factor(num / divisor); + factors +} + pub fn factor(mut n: u64) -> Factors { let mut factors = Factors::one(); @@ -88,8 +116,10 @@ pub fn factor(mut n: u64) -> Factors { let (f, n) = table::factor(n); factors *= f; - if n >= table::NEXT_PRIME { - factors *= rho::factor(n); + if n < (1 << 32) { + factors *= _factor::(n); + } else { + factors *= _factor::(n); } factors diff --git a/src/uu/factor/src/rho.rs b/src/uu/factor/src/rho.rs index 9a53a40f4..b28e88e91 100644 --- a/src/uu/factor/src/rho.rs +++ b/src/uu/factor/src/rho.rs @@ -11,11 +11,9 @@ use rand::rngs::SmallRng; use rand::{thread_rng, SeedableRng}; use std::cmp::{max, min}; -use crate::miller_rabin::Result::*; use crate::numeric::*; -use crate::{miller_rabin, Factors}; -fn find_divisor(n: A) -> u64 { +pub(crate) fn find_divisor(n: A) -> u64 { #![allow(clippy::many_single_char_names)] let mut rand = { let range = Uniform::new(1, n.modulus()); @@ -47,33 +45,3 @@ fn find_divisor(n: A) -> u64 { } } } - -fn _factor(num: u64) -> Factors { - // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small. - let _factor = |n| { - // TODO: Optimise with 32 and 64b versions - _factor::(n) - }; - - if num == 1 { - return Factors::one(); - } - - let n = A::new(num); - let divisor = match miller_rabin::test::(n) { - Prime => { - return Factors::prime(num); - } - - Composite(d) => d, - Pseudoprime => find_divisor::(n), - }; - - let mut factors = _factor(divisor); - factors *= _factor(num / divisor); - factors -} - -pub(crate) fn factor(n: u64) -> Factors { - _factor::(n) -} From 2d2b6faab478569df3e80728a9fcadc3a2157b5e Mon Sep 17 00:00:00 2001 From: nicoo Date: Thu, 25 Jun 2020 03:45:46 +0200 Subject: [PATCH 3/9] factor: Avoid moving data around in main factoring loop Instead, the same `Factors` object is passed around through the execution. ~10% faster. --- src/uu/factor/src/factor.rs | 35 ++++++++++++----------------------- src/uu/factor/src/table.rs | 3 +-- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/src/uu/factor/src/factor.rs b/src/uu/factor/src/factor.rs index f77792a58..f7903075a 100644 --- a/src/uu/factor/src/factor.rs +++ b/src/uu/factor/src/factor.rs @@ -9,7 +9,6 @@ extern crate rand; use std::collections::BTreeMap; use std::fmt; -use std::ops; use crate::numeric::{Arithmetic, Montgomery}; use crate::{miller_rabin, rho, table}; @@ -48,14 +47,6 @@ impl Factors { } } -impl ops::MulAssign for Factors { - fn mul_assign(&mut self, other: Factors) { - for (prime, exp) in &other.f { - self.add(*prime, *exp); - } - } -} - impl fmt::Display for Factors { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for (p, exp) in self.f.iter() { @@ -68,31 +59,32 @@ impl fmt::Display for Factors { } } -fn _factor(num: u64) -> Factors { +fn _factor(num: u64, f: Factors) -> Factors { use miller_rabin::Result::*; // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small. - let _factor = |n| { + let _factor = |n, f| { // TODO: Optimise with 32 and 64b versions - _factor::(n) + _factor::(n, f) }; if num == 1 { - return Factors::one(); + return f; } let n = A::new(num); let divisor = match miller_rabin::test::(n) { Prime => { - return Factors::prime(num); + let mut r = f; + r.push(num); + return r; } Composite(d) => d, Pseudoprime => rho::find_divisor::(n), }; - let mut factors = _factor(divisor); - factors *= _factor(num / divisor); - factors + let f = _factor(divisor, f); + _factor(num / divisor, f) } pub fn factor(mut n: u64) -> Factors { @@ -113,16 +105,13 @@ pub fn factor(mut n: u64) -> Factors { return factors; } - let (f, n) = table::factor(n); - factors *= f; + let (factors, n) = table::factor(n, factors); if n < (1 << 32) { - factors *= _factor::(n); + _factor::(n, factors) } else { - factors *= _factor::(n); + _factor::(n, factors) } - - factors } #[cfg(test)] diff --git a/src/uu/factor/src/table.rs b/src/uu/factor/src/table.rs index 9d18c9d27..d6ef796fc 100644 --- a/src/uu/factor/src/table.rs +++ b/src/uu/factor/src/table.rs @@ -14,8 +14,7 @@ use crate::Factors; include!(concat!(env!("OUT_DIR"), "/prime_table.rs")); -pub(crate) fn factor(mut num: u64) -> (Factors, u64) { - let mut factors = Factors::one(); +pub(crate) fn factor(mut num: u64, mut factors: Factors) -> (Factors, u64) { for &(prime, inv, ceil) in P_INVS_U64 { if num == 1 { break; From f1d1cb80e47a76de3a7166282f7f000abc8fa3c4 Mon Sep 17 00:00:00 2001 From: nicoo Date: Wed, 1 Jul 2020 00:17:38 +0200 Subject: [PATCH 4/9] factor::Factors: Generalise invariant check (from prime() to add()) --- src/uu/factor/src/factor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/factor/src/factor.rs b/src/uu/factor/src/factor.rs index f7903075a..bcf570972 100644 --- a/src/uu/factor/src/factor.rs +++ b/src/uu/factor/src/factor.rs @@ -23,13 +23,13 @@ impl Factors { } pub fn prime(p: u64) -> Factors { - debug_assert!(miller_rabin::is_prime(p)); let mut f = Factors::one(); f.push(p); f } pub fn add(&mut self, prime: u64, exp: u8) { + debug_assert!(miller_rabin::is_prime(prime)); debug_assert!(exp > 0); let n = *self.f.get(&prime).unwrap_or(&0); self.f.insert(prime, exp + n); From dcc22188ba54d125cb3e824acc35512de26bc873 Mon Sep 17 00:00:00 2001 From: nicoo Date: Wed, 1 Jul 2020 00:21:18 +0200 Subject: [PATCH 5/9] factor: Fix clippy warnings --- src/uu/factor/src/factor.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/uu/factor/src/factor.rs b/src/uu/factor/src/factor.rs index bcf570972..c0b6ea964 100644 --- a/src/uu/factor/src/factor.rs +++ b/src/uu/factor/src/factor.rs @@ -22,12 +22,6 @@ impl Factors { Factors { f: BTreeMap::new() } } - pub fn prime(p: u64) -> Factors { - let mut f = Factors::one(); - f.push(p); - f - } - pub fn add(&mut self, prime: u64, exp: u8) { debug_assert!(miller_rabin::is_prime(prime)); debug_assert!(exp > 0); @@ -107,11 +101,8 @@ pub fn factor(mut n: u64) -> Factors { let (factors, n) = table::factor(n, factors); - if n < (1 << 32) { - _factor::(n, factors) - } else { - _factor::(n, factors) - } + // TODO: Optimise with 32 and 64b versions + _factor::(n, factors) } #[cfg(test)] From 7bdc81b882497c4f7cbc582eb1a300845fd76b20 Mon Sep 17 00:00:00 2001 From: nicoo Date: Sat, 4 Jul 2020 12:55:04 +0200 Subject: [PATCH 6/9] factor: Add a first property-based test --- Cargo.lock | 25 +++++++++++++++++++++++++ src/uu/factor/Cargo.toml | 3 +++ src/uu/factor/src/factor.rs | 7 +++++++ 3 files changed, 35 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 25997280c..bf827342f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "advapi32-sys" version = "0.2.0" @@ -367,6 +369,15 @@ name = "either" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "failure" version = "0.1.1" @@ -670,6 +681,17 @@ name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "quickcheck" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "0.3.15" @@ -1313,6 +1335,7 @@ dependencies = [ name = "uu_factor" version = "0.0.1" dependencies = [ + "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "uucore 0.0.4 (git+https://github.com/uutils/uucore.git?branch=canary)", "uucore_procs 0.0.4 (git+https://github.com/uutils/uucore.git?branch=canary)", @@ -2193,6 +2216,7 @@ dependencies = [ "checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a" "checksum dunce 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b2641c4a7c0c4101df53ea572bffdc561c146f6c2eb09e4df02bc4811e3feeb4" "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" @@ -2234,6 +2258,7 @@ dependencies = [ "checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" "checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +"checksum quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a44883e74aa97ad63db83c4bf8ca490f02b2fc02f92575e720c8551e843c945f" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" "checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" diff --git a/src/uu/factor/Cargo.toml b/src/uu/factor/Cargo.toml index 5631a52da..0005de0a1 100644 --- a/src/uu/factor/Cargo.toml +++ b/src/uu/factor/Cargo.toml @@ -16,6 +16,9 @@ rand = "0.5" uucore = { version="0.0.4", package="uucore", git="https://github.com/uutils/uucore.git", branch="canary" } uucore_procs = { version="0.0.4", package="uucore_procs", git="https://github.com/uutils/uucore.git", branch="canary" } +[dev-dependencies] +quickcheck = "0.9.2" + [[bin]] name = "factor" path = "src/main.rs" diff --git a/src/uu/factor/src/factor.rs b/src/uu/factor/src/factor.rs index c0b6ea964..e86787a36 100644 --- a/src/uu/factor/src/factor.rs +++ b/src/uu/factor/src/factor.rs @@ -108,6 +108,7 @@ pub fn factor(mut n: u64) -> Factors { #[cfg(test)] mod tests { use super::factor; + use quickcheck::quickcheck; #[test] fn factor_recombines_small() { @@ -135,4 +136,10 @@ mod tests { assert!(factor(pseudoprime).product() == pseudoprime); } } + + quickcheck! { + fn factor_recombines(i: u64) -> bool { + i == 0 || factor(i).product() == i + } + } } From e9e263ac6654c239231302b0929bfac330a92370 Mon Sep 17 00:00:00 2001 From: nicoo Date: Sat, 4 Jul 2020 12:55:33 +0200 Subject: [PATCH 7/9] factor::Factors: Derive Clone and Debug Useful for printing out in-progress factorisations when debugging. --- src/uu/factor/src/factor.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/uu/factor/src/factor.rs b/src/uu/factor/src/factor.rs index e86787a36..a27c86c62 100644 --- a/src/uu/factor/src/factor.rs +++ b/src/uu/factor/src/factor.rs @@ -13,6 +13,7 @@ use std::fmt; use crate::numeric::{Arithmetic, Montgomery}; use crate::{miller_rabin, rho, table}; +#[derive(Clone, Debug)] pub struct Factors { f: BTreeMap, } From 9b0f13113530f79ecd84087150d0c23a9764708e Mon Sep 17 00:00:00 2001 From: nicoo Date: Sat, 4 Jul 2020 12:56:25 +0200 Subject: [PATCH 8/9] Fix bug in factor::factor::factor (>_>") Non-prime numbers, such as 0 or 1, shouldn't be inserted in the factorisation. --- src/uu/factor/src/factor.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/uu/factor/src/factor.rs b/src/uu/factor/src/factor.rs index a27c86c62..1e4e4087b 100644 --- a/src/uu/factor/src/factor.rs +++ b/src/uu/factor/src/factor.rs @@ -86,7 +86,6 @@ pub fn factor(mut n: u64) -> Factors { let mut factors = Factors::one(); if n < 2 { - factors.push(n); return factors; } From 4cfe754551919c64f0619f3aab477c25cd204a9f Mon Sep 17 00:00:00 2001 From: nicoo Date: Sat, 4 Jul 2020 12:58:09 +0200 Subject: [PATCH 9/9] factor::miller_rabin::is_prime: Fix bug Montgomery only works for odd n, so attempting to construct an instance for an even number results in a panic! The most obvious solution is to special-case even numbers. --- src/uu/factor/src/miller_rabin.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/uu/factor/src/miller_rabin.rs b/src/uu/factor/src/miller_rabin.rs index d133bc674..c71b7c825 100644 --- a/src/uu/factor/src/miller_rabin.rs +++ b/src/uu/factor/src/miller_rabin.rs @@ -84,10 +84,14 @@ pub(crate) fn test(m: A) -> Result { Prime } -// Used by build.rs' tests +// Used by build.rs' tests and debug assertions #[allow(dead_code)] pub(crate) fn is_prime(n: u64) -> bool { - test::(Montgomery::new(n)).is_prime() + if n % 2 == 0 { + n == 2 + } else { + test::(Montgomery::new(n)).is_prime() + } } #[cfg(test)]