diff --git a/src/uu/factor/src/factor.rs b/src/uu/factor/src/factor.rs index 81f655eb7..334fe644a 100644 --- a/src/uu/factor/src/factor.rs +++ b/src/uu/factor/src/factor.rs @@ -23,9 +23,12 @@ use rand::distributions::{Distribution, Uniform}; use rand::rngs::SmallRng; use rand::{thread_rng, SeedableRng}; use std::cmp::{max, min}; +use std::collections::HashMap; +use std::fmt; use std::io::{stdin, BufRead}; use std::mem::swap; use std::num::Wrapping; +use std::ops; mod numeric; @@ -36,14 +39,6 @@ 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 rho_pollard_pseudorandom_function(x: u64, a: u64, b: u64, num: u64) -> u64 { - if num < 1 << 63 { - (sm_mul(a, sm_mul(x, x, num), num) + b) % num - } else { - big_add(big_mul(a, big_mul(x, x, num), num), b, num) - } -} - fn gcd(mut a: u64, mut b: u64) -> u64 { while b > 0 { a %= b; @@ -52,6 +47,58 @@ fn gcd(mut a: u64, mut b: u64) -> u64 { a } +struct Factors { + f: HashMap, +} + +impl Factors { + fn new() -> Factors { + Factors { f: HashMap::new() } + } + + fn add(&mut self, prime: u64, exp: u8) { + assert!(exp > 0); + self.f.insert(prime, exp + self.f.get(&prime).unwrap_or(&0)); + } + + fn push(&mut self, prime: u64) { + self.add(prime, 1) + } +} + +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 { + // TODO: Use a representation with efficient in-order iteration + let mut primes: Vec<&u64> = self.f.keys().collect(); + primes.sort(); + + for p in primes { + for _ in 0..self.f[&p] { + write!(f, " {}", p)? + } + } + + Ok(()) + } +} + + +fn rho_pollard_pseudorandom_function(x: u64, a: u64, b: u64, num: u64) -> u64 { + if num < 1 << 63 { + (sm_mul(a, sm_mul(x, x, num), num) + b) % num + } else { + big_add(big_mul(a, big_mul(x, x, num), num), b, num) + } +} + fn rho_pollard_find_divisor(num: u64) -> u64 { #![allow(clippy::many_single_char_names)] let range = Uniform::new(1, num); @@ -78,31 +125,39 @@ fn rho_pollard_find_divisor(num: u64) -> u64 { } } -fn rho_pollard_factor(num: u64, factors: &mut Vec) { +fn rho_pollard_factor(num: u64, factors: &mut Factors) { if is_prime(num) { factors.push(num); return; } + let divisor = rho_pollard_find_divisor(num); rho_pollard_factor(divisor, factors); rho_pollard_factor(num / divisor, factors); } -fn table_division(mut num: u64, factors: &mut Vec) { +fn table_division(mut num: u64) -> Factors { + let mut factors = Factors::new(); + if num < 2 { - return; + factors.push(num); + return factors } + while num % 2 == 0 { num /= 2; factors.push(2); } + if num == 1 { - return; + return factors; } + if is_prime(num) { factors.push(num); - return; + return factors; } + for &(prime, inv, ceil) in P_INVS_U64 { if num == 1 { break; @@ -120,7 +175,7 @@ fn table_division(mut num: u64, factors: &mut Vec) { factors.push(prime); if is_prime(num) { factors.push(num); - return; + return factors; } } else { break; @@ -136,21 +191,13 @@ fn table_division(mut num: u64, factors: &mut Vec) { //trial_division_slow(num, factors); //} else if num > 1 { // number is still greater than 1, but not so big that we have to worry - rho_pollard_factor(num, factors); + rho_pollard_factor(num, &mut factors); + factors //} } fn print_factors(num: u64) { - print!("{}:", num); - - let mut factors = Vec::new(); - // we always start with table division, and go from there - table_division(num, &mut factors); - factors.sort(); - - for fac in &factors { - print!(" {}", fac); - } + print!("{}:{}", num, table_division(num)); println!(); }