mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-08-04 23:17:46 +00:00
factor: Refactor (eheh) around a Factors
datatype
It is clearer to see what is going on, as opposed to passing around an unmarked `Vec<u64>`, and there is a single place to add invariants checks. This is also a more compact memory representation: each prime factor is represented only once, with an additional byte for multiplicity. The performance impact is however not significant.
This commit is contained in:
parent
272b66aac8
commit
d9095a2539
1 changed files with 72 additions and 25 deletions
|
@ -23,9 +23,12 @@ use rand::distributions::{Distribution, Uniform};
|
||||||
use rand::rngs::SmallRng;
|
use rand::rngs::SmallRng;
|
||||||
use rand::{thread_rng, SeedableRng};
|
use rand::{thread_rng, SeedableRng};
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt;
|
||||||
use std::io::{stdin, BufRead};
|
use std::io::{stdin, BufRead};
|
||||||
use std::mem::swap;
|
use std::mem::swap;
|
||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
|
use std::ops;
|
||||||
|
|
||||||
mod numeric;
|
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.";
|
If none are specified, read from standard input.";
|
||||||
static LONG_HELP: &str = "";
|
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 {
|
fn gcd(mut a: u64, mut b: u64) -> u64 {
|
||||||
while b > 0 {
|
while b > 0 {
|
||||||
a %= b;
|
a %= b;
|
||||||
|
@ -52,6 +47,58 @@ fn gcd(mut a: u64, mut b: u64) -> u64 {
|
||||||
a
|
a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Factors {
|
||||||
|
f: HashMap<u64, u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<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 {
|
||||||
|
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 {
|
fn rho_pollard_find_divisor(num: u64) -> u64 {
|
||||||
#![allow(clippy::many_single_char_names)]
|
#![allow(clippy::many_single_char_names)]
|
||||||
let range = Uniform::new(1, num);
|
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<u64>) {
|
fn rho_pollard_factor(num: u64, factors: &mut Factors) {
|
||||||
if is_prime(num) {
|
if is_prime(num) {
|
||||||
factors.push(num);
|
factors.push(num);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let divisor = rho_pollard_find_divisor(num);
|
let divisor = rho_pollard_find_divisor(num);
|
||||||
rho_pollard_factor(divisor, factors);
|
rho_pollard_factor(divisor, factors);
|
||||||
rho_pollard_factor(num / divisor, factors);
|
rho_pollard_factor(num / divisor, factors);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table_division(mut num: u64, factors: &mut Vec<u64>) {
|
fn table_division(mut num: u64) -> Factors {
|
||||||
|
let mut factors = Factors::new();
|
||||||
|
|
||||||
if num < 2 {
|
if num < 2 {
|
||||||
return;
|
factors.push(num);
|
||||||
|
return factors
|
||||||
}
|
}
|
||||||
|
|
||||||
while num % 2 == 0 {
|
while num % 2 == 0 {
|
||||||
num /= 2;
|
num /= 2;
|
||||||
factors.push(2);
|
factors.push(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if num == 1 {
|
if num == 1 {
|
||||||
return;
|
return factors;
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_prime(num) {
|
if is_prime(num) {
|
||||||
factors.push(num);
|
factors.push(num);
|
||||||
return;
|
return factors;
|
||||||
}
|
}
|
||||||
|
|
||||||
for &(prime, inv, ceil) in P_INVS_U64 {
|
for &(prime, inv, ceil) in P_INVS_U64 {
|
||||||
if num == 1 {
|
if num == 1 {
|
||||||
break;
|
break;
|
||||||
|
@ -120,7 +175,7 @@ fn table_division(mut num: u64, factors: &mut Vec<u64>) {
|
||||||
factors.push(prime);
|
factors.push(prime);
|
||||||
if is_prime(num) {
|
if is_prime(num) {
|
||||||
factors.push(num);
|
factors.push(num);
|
||||||
return;
|
return factors;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -136,21 +191,13 @@ fn table_division(mut num: u64, factors: &mut Vec<u64>) {
|
||||||
//trial_division_slow(num, factors);
|
//trial_division_slow(num, factors);
|
||||||
//} else if num > 1 {
|
//} else if num > 1 {
|
||||||
// number is still greater than 1, but not so big that we have to worry
|
// 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) {
|
fn print_factors(num: u64) {
|
||||||
print!("{}:", num);
|
print!("{}:{}", num, table_division(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);
|
|
||||||
}
|
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue