1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 03:27:44 +00:00

factor::miller_rabin: Avoid unecessary exponentiation

Instead of computing a^r and a^(n-1) = a^(r 2ⁱ) separately,
compute the latter by repeatedly squaring the former.

33.6% performance improvement
This commit is contained in:
nicoo 2020-05-24 19:10:34 +02:00
parent 543c7b941a
commit 36a2948959

View file

@ -20,6 +20,7 @@ impl Result {
// Deterministic Miller-Rabin primality-checking algorithm, adapted to extract
// (some) dividers; it will fail to factor strong pseudoprimes.
#[allow(clippy::many_single_char_names)]
pub(crate) fn test<A: Arithmetic>(n: u64) -> Result {
use self::Result::*;
@ -30,18 +31,30 @@ pub(crate) fn test<A: Arithmetic>(n: u64) -> Result {
return if n == 2 { Prime } else { Composite(2) };
}
let r = (n - 1) >> (n - 1).trailing_zeros();
// n-1 = r 2ⁱ
let i = (n - 1).trailing_zeros();
let r = (n - 1) >> i;
for a in BASIS.iter() {
let mut x = a % n;
if x == 0 {
let a = a % n;
if a == 0 {
break;
}
if A::pow(x, n - 1, n) != 1 {
return Pseudoprime;
// x = a^r mod n
let mut x = A::pow(a, r, n);
{
// y = ((x²)²...)² i times = x ^ (2ⁱ) = a ^ (r 2ⁱ) = x ^ (n - 1)
let mut y = x;
for _ in 0..i {
y = A::mul(y, y, n)
}
if y != 1 {
return Pseudoprime;
};
}
x = A::pow(x, r, n);
if x == 1 || x == n - 1 {
break;
}