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

factor: Avoid moving data around in main factoring loop

Instead, the same `Factors` object is passed around through the execution.
~10% faster.
This commit is contained in:
nicoo 2020-06-25 03:45:46 +02:00
parent 6713d2ad62
commit 2d2b6faab4
2 changed files with 13 additions and 25 deletions

View file

@ -9,7 +9,6 @@ extern crate rand;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt; use std::fmt;
use std::ops;
use crate::numeric::{Arithmetic, Montgomery}; use crate::numeric::{Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table}; use crate::{miller_rabin, rho, table};
@ -48,14 +47,6 @@ impl Factors {
} }
} }
impl ops::MulAssign<Factors> for Factors {
fn mul_assign(&mut self, other: Factors) {
for (prime, exp) in &other.f {
self.add(*prime, *exp);
}
}
}
impl fmt::Display for Factors { impl fmt::Display for Factors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (p, exp) in self.f.iter() { for (p, exp) in self.f.iter() {
@ -68,31 +59,32 @@ impl fmt::Display for Factors {
} }
} }
fn _factor<A: Arithmetic>(num: u64) -> Factors { fn _factor<A: Arithmetic>(num: u64, f: Factors) -> Factors {
use miller_rabin::Result::*; use miller_rabin::Result::*;
// 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, f| {
// TODO: Optimise with 32 and 64b versions // TODO: Optimise with 32 and 64b versions
_factor::<A>(n) _factor::<A>(n, f)
}; };
if num == 1 { if num == 1 {
return Factors::one(); return f;
} }
let n = A::new(num); let n = A::new(num);
let divisor = match miller_rabin::test::<A>(n) { let divisor = match miller_rabin::test::<A>(n) {
Prime => { Prime => {
return Factors::prime(num); let mut r = f;
r.push(num);
return r;
} }
Composite(d) => d, Composite(d) => d,
Pseudoprime => rho::find_divisor::<A>(n), Pseudoprime => rho::find_divisor::<A>(n),
}; };
let mut factors = _factor(divisor); let f = _factor(divisor, f);
factors *= _factor(num / divisor); _factor(num / divisor, f)
factors
} }
pub fn factor(mut n: u64) -> Factors { pub fn factor(mut n: u64) -> Factors {
@ -113,16 +105,13 @@ pub fn factor(mut n: u64) -> Factors {
return factors; return factors;
} }
let (f, n) = table::factor(n); let (factors, n) = table::factor(n, factors);
factors *= f;
if n < (1 << 32) { if n < (1 << 32) {
factors *= _factor::<Montgomery>(n); _factor::<Montgomery>(n, factors)
} else { } else {
factors *= _factor::<Montgomery>(n); _factor::<Montgomery>(n, factors)
} }
factors
} }
#[cfg(test)] #[cfg(test)]

View file

@ -14,8 +14,7 @@ use crate::Factors;
include!(concat!(env!("OUT_DIR"), "/prime_table.rs")); include!(concat!(env!("OUT_DIR"), "/prime_table.rs"));
pub(crate) fn factor(mut num: u64) -> (Factors, u64) { pub(crate) fn factor(mut num: u64, mut factors: Factors) -> (Factors, u64) {
let mut factors = Factors::one();
for &(prime, inv, ceil) in P_INVS_U64 { for &(prime, inv, ceil) in P_INVS_U64 {
if num == 1 { if num == 1 {
break; break;