1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-08-04 23:17:46 +00:00

factor::miller_rabin: Use a specialized basis for 32b integers

~3% faster
This commit is contained in:
nicoo 2020-06-21 17:00:46 +02:00
parent e68bb192f2
commit a440807e6c
2 changed files with 25 additions and 8 deletions

View file

@ -2,10 +2,27 @@
use crate::numeric::*; use crate::numeric::*;
pub(crate) trait Basis {
const BASIS: &'static [u64];
}
impl Basis for Montgomery {
// Small set of bases for the Miller-Rabin prime test, valid for all 64b integers; // Small set of bases for the Miller-Rabin prime test, valid for all 64b integers;
// discovered by Jim Sinclair on 2011-04-20, see miller-rabin.appspot.com // discovered by Jim Sinclair on 2011-04-20, see miller-rabin.appspot.com
#[allow(clippy::unreadable_literal)] #[allow(clippy::unreadable_literal)]
const BASIS: [u64; 7] = [2, 325, 9375, 28178, 450775, 9780504, 1795265022]; const BASIS: &'static [u64] = &[2, 325, 9375, 28178, 450775, 9780504, 1795265022];
}
impl Basis for Montgomery32 {
// Small set of bases for the Miller-Rabin prime test, valid for all 32b integers;
// discovered by Steve Worley on 2013-05-27, see miller-rabin.appspot.com
#[allow(clippy::unreadable_literal)]
const BASIS: &'static [u64] = &[
4230279247111683200,
14694767155120705706,
16641139526367750375,
];
}
#[derive(Eq, PartialEq)] #[derive(Eq, PartialEq)]
pub(crate) enum Result { pub(crate) enum Result {
@ -23,7 +40,7 @@ impl Result {
// Deterministic Miller-Rabin primality-checking algorithm, adapted to extract // Deterministic Miller-Rabin primality-checking algorithm, adapted to extract
// (some) dividers; it will fail to factor strong pseudoprimes. // (some) dividers; it will fail to factor strong pseudoprimes.
#[allow(clippy::many_single_char_names)] #[allow(clippy::many_single_char_names)]
pub(crate) fn test<A: Arithmetic>(m: A) -> Result { pub(crate) fn test<A: Arithmetic + Basis>(m: A) -> Result {
use self::Result::*; use self::Result::*;
let n = m.modulus(); let n = m.modulus();
@ -41,7 +58,7 @@ pub(crate) fn test<A: Arithmetic>(m: A) -> Result {
let one = m.one(); let one = m.one();
let minus_one = m.minus_one(); let minus_one = m.minus_one();
for _a in BASIS.iter() { for _a in A::BASIS.iter() {
let _a = _a % n; let _a = _a % n;
if _a == 0 { if _a == 0 {
break; break;

View file

@ -15,7 +15,7 @@ use crate::miller_rabin::Result::*;
use crate::numeric::*; use crate::numeric::*;
use crate::{miller_rabin, Factors}; use crate::{miller_rabin, Factors};
fn find_divisor<A: Arithmetic>(n: A) -> u64 { fn find_divisor<A: Arithmetic + miller_rabin::Basis>(n: A) -> u64 {
#![allow(clippy::many_single_char_names)] #![allow(clippy::many_single_char_names)]
let mut rand = { let mut rand = {
let range = Uniform::new(1, n.modulus()); let range = Uniform::new(1, n.modulus());
@ -48,7 +48,7 @@ fn find_divisor<A: Arithmetic>(n: A) -> u64 {
} }
} }
fn _factor<A: Arithmetic>(num: u64) -> Factors { fn _factor<A: Arithmetic + miller_rabin::Basis>(num: u64) -> Factors {
// Shadow the name, so the recursion automatically goes from “Big” arithmetic to small. // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small.
let _factor = |n| { let _factor = |n| {
if n < (1 << 32) { if n < (1 << 32) {