mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 20:17:45 +00:00
factor::miller_rabin: Extract dividers from the primality test
Another 36% improvement.
This commit is contained in:
parent
6b9585b1dc
commit
8241037690
2 changed files with 42 additions and 11 deletions
|
@ -4,14 +4,29 @@ use crate::numeric::*;
|
|||
// discovered by Jim Sinclair on 2011-04-20, see miller-rabin.appspot.com
|
||||
const BASIS: [u64; 7] = [2, 325, 9375, 28178, 450775, 9780504, 1795265022];
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub(crate) enum Result {
|
||||
Prime,
|
||||
Pseudoprime,
|
||||
Composite(u64),
|
||||
}
|
||||
|
||||
impl Result {
|
||||
pub(crate) fn is_prime(&self) -> bool {
|
||||
return *self == Result::Prime;
|
||||
}
|
||||
}
|
||||
|
||||
// Deterministic Miller-Rabin primality-checking algorithm, adapted to extract
|
||||
// (some) dividers; it will fail to factor strong pseudoprimes.
|
||||
pub(crate) fn is_prime(n: u64) -> bool {
|
||||
pub(crate) fn test(n: u64) -> Result {
|
||||
use self::Result::*;
|
||||
|
||||
if n < 2 {
|
||||
return false;
|
||||
return Pseudoprime;
|
||||
}
|
||||
if n % 2 == 0 {
|
||||
return n == 2;
|
||||
return if n == 2 { Prime } else { Composite(2) };
|
||||
}
|
||||
|
||||
let d = (n - 1).trailing_zeros();
|
||||
|
@ -30,7 +45,7 @@ pub(crate) fn is_prime(n: u64) -> bool {
|
|||
}
|
||||
|
||||
if pow(x, n - 1, n, mul) != 1 {
|
||||
return false;
|
||||
return Pseudoprime;
|
||||
}
|
||||
x = pow(x, r, n, mul);
|
||||
if x == 1 || x == n - 1 {
|
||||
|
@ -40,7 +55,7 @@ pub(crate) fn is_prime(n: u64) -> bool {
|
|||
loop {
|
||||
let y = mul(x, x, n);
|
||||
if y == 1 {
|
||||
return false;
|
||||
return Composite(gcd(x - 1, n));
|
||||
}
|
||||
if y == n - 1 {
|
||||
// This basis element is not a witness of `n` being composite.
|
||||
|
@ -51,5 +66,11 @@ pub(crate) fn is_prime(n: u64) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
true
|
||||
Prime
|
||||
}
|
||||
|
||||
// Used by build.rs' tests
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn is_prime(n: u64) -> bool {
|
||||
test(n).is_prime()
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::miller_rabin::Result::*;
|
||||
use crate::{miller_rabin, Factors};
|
||||
use numeric::*;
|
||||
use rand::distributions::{Distribution, Uniform};
|
||||
|
@ -39,16 +40,25 @@ fn find_divisor(num: u64) -> u64 {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn factor(num: u64) -> Factors {
|
||||
pub(crate) fn factor(mut num: u64) -> Factors {
|
||||
let mut factors = Factors::new();
|
||||
if num == 1 {
|
||||
return factors;
|
||||
}
|
||||
|
||||
if miller_rabin::is_prime(num) {
|
||||
factors.push(num);
|
||||
return factors;
|
||||
}
|
||||
match miller_rabin::test(num) {
|
||||
Prime => {
|
||||
factors.push(num);
|
||||
return factors;
|
||||
}
|
||||
|
||||
Composite(d) => {
|
||||
num = num / d;
|
||||
factors *= factor(d);
|
||||
}
|
||||
|
||||
Pseudoprime => {}
|
||||
};
|
||||
|
||||
let divisor = find_divisor(num);
|
||||
factors *= factor(divisor);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue