1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
//! Module dedicated to factorizing numbers
use super::{PrimeData, utils::IntSqrt};
use std::collections::HashMap;
/// Retrieves every factor of x
///
/// *This function is only available with the `factors` feature enabled.*
///
/// A factor is any number that divides x. Therefore, it includes 1 and x itself.
///
/// This function is simply an abstraction over creating the [`Factorization`] struct
/// and calling [`Factorization::all_factors`].
///
/// **Note**: The returned vector will have length 1, if and only if x is 1. It will have
/// length 2 if and only if x is prime. However, it's much faster to verify if a number
/// is prime using [PrimeData](`crate::PrimeData`).
///
/// # Examples
///
/// ```
/// use prime_data::all_factors_of;
///
/// assert_eq!(all_factors_of(1), vec![1]);
/// assert_eq!(all_factors_of(3), vec![1, 3]);
/// assert_eq!(all_factors_of(6), vec![1, 2, 3, 6]);
/// ```
pub fn all_factors_of(x: u64) -> Vec<u64> {
Factorization::from(x).all_factors()
}
/// Represents some number into its prime-factorized form
///
/// *This struct is only available with the `factors` feature enabled.*
pub struct Factorization {
data: HashMap<u64, u32>
}
impl Factorization {
/// Converts some factorization into the original number without consuming itself
///
/// # Examples
///
/// ```
/// use prime_data::Factorization;
///
/// assert_eq!(1, Factorization::from(1).as_u64());
/// assert_eq!(12, Factorization::from(12).as_u64());
/// assert_eq!(29375346, Factorization::from(29375346).as_u64());
/// ```
pub fn as_u64(&self) -> u64 {
self.data.iter()
.fold(1u64, |acc, (&prime, &amount)| acc * prime.pow(amount))
}
/// Retrieves the factorization as a tuple (prime, amount)
///
/// Note that if the vector is empty, it means the original number is 1.
///
/// # Examples
///
/// ```
/// use prime_data::Factorization;
///
/// // 43560 = 2^3 * 3^2 * 5 * 11^2
/// let factorization = Factorization::from(43560);
/// assert_eq!(
/// factorization.as_tuples(),
/// vec![(2, 3), (3, 2), (5, 1), (11, 2)]
/// );
/// ```
pub fn as_tuples(&self) -> Vec<(u64, u32)> {
let mut vec: Vec<(u64, u32)> = self.data.iter().map(|(&p, &c)| (p, c)).collect();
vec.sort_by(|a, b| a.0.cmp(&(b.0)));
vec
}
/// Retrieves all possible factors of the factorized number
///
/// It does so by multiplying every possible combination of its prime factors.
///
/// **Note**: Includes 1 and itself. Therefore, the minimal length for this vector
/// is 1, happening when the original numbers is 1, then length 2, if and only if
/// the original number is prime.
///
/// # Examples
///
/// ```
/// use prime_data::Factorization;
///
/// let thirty = Factorization::from(30);
/// assert_eq!(
/// thirty.all_factors(),
/// vec![1, 2, 3, 5, 6, 10, 15, 30]
/// );
/// ```
pub fn all_factors(&self) -> Vec<u64> {
let tuples = self.as_tuples();
let mut vector = Self::factor_combos(&tuples);
vector.sort();
vector
}
}
// private methods
impl Factorization {
pub(crate) fn new() -> Self {
Self { data: HashMap::new() }
}
pub(crate) fn add_factor(&mut self, factor: u64) {
if let Some(amount) = self.data.get_mut(&factor) {
*amount += 1;
} else {
self.data.insert(factor, 1);
}
}
pub(crate) fn is_empty(&self) -> bool {
self.data.is_empty()
}
fn factor_combos(slice: &[(u64, u32)]) -> Vec<u64> {
if slice.len() == 0 {
vec![1]
} else {
let inner_combos = Self::factor_combos(&slice[1..]);
let (this_prime, amount) = slice[0];
let mut combinations = Vec::new();
for pow in 0..=amount {
let new_factor = this_prime.pow(pow);
combinations.append(&mut (inner_combos.iter().map(|&x| new_factor * x).collect()));
}
combinations
}
}
}
impl From<u64> for Factorization {
fn from(number: u64) -> Factorization {
let prime_data = PrimeData::generate(0..=(number.sqrt_floor()));
prime_data.factorize(number)
}
}