Skip to main content

fast_factor/
lib.rs

1//! A reasonably fast factorisation library for unsigned integers.
2//!
3//! # Examples
4//!
5//! ```
6//! assert_eq!(fast_factor::factor(24_u32), vec![1,2,3,4,6,8,12,24]);
7//! assert_eq!(fast_factor::proper_factor(24_u32), vec![1,2,3,4,6,8,12]);
8//! assert_eq!(fast_factor::exclusive_factor(24_u32), vec![2,3,4,6,8,12]);
9//! ```
10
11use num_integer::Roots;
12use num_traits::{PrimInt, Unsigned};
13
14/// For non-zero inputs, which must be unsigned integers, returns all factors of the number given, including one and the number itself, as a vector. Returns an empty vector for zero.
15///
16/// # Examples
17///
18/// ```
19/// assert_eq!(fast_factor::factor(0_u32), vec![]);
20/// assert_eq!(fast_factor::factor(1_u32), vec![1]);
21/// assert_eq!(fast_factor::factor(7_u32), vec![1,7]);
22/// assert_eq!(fast_factor::factor(12_u32), vec![1,2,3,4,6,12]);
23/// assert_eq!(fast_factor::factor(36_u32), vec![1,2,3,4,6,9,12,18,36]);
24/// ```
25pub fn factor<T: PrimInt + Unsigned + Roots>(n: T) -> Vec<T> {
26    let mut factors: Vec<T> = Vec::new();
27    let zero = T::zero();
28    let one = T::one();
29    let two = one + one;
30    if n == zero {
31        return factors;
32    }
33
34    factors.push(one);
35    let root_n = n.sqrt();
36    let mut factor = two;
37    while factor <= root_n {
38        if n % factor == zero {
39            factors.push(factor);
40        }
41        factor = factor + one;
42    }
43    let is_square = root_n * root_n == n;
44    let mid = factors.len();
45    for index in (0..mid).rev() {
46        let factor = factors[index];
47        if !(is_square && factor == root_n) {
48            factors.push(n / factor);
49        }
50    }
51    factors
52}
53
54/// For all unsigned integer inputs, returns all factors of the number, excluding the number
55/// itself.
56///
57/// # Examples
58///
59/// ```
60/// assert_eq!(fast_factor::proper_factor(0_u32), vec![]);
61/// assert_eq!(fast_factor::proper_factor(1_u32), vec![]);
62/// assert_eq!(fast_factor::proper_factor(7_u32), vec![1]);
63/// assert_eq!(fast_factor::proper_factor(12_u32), vec![1,2,3,4,6]);
64/// assert_eq!(fast_factor::proper_factor(36_u32), vec![1,2,3,4,6,9,12,18]);
65/// ```
66pub fn proper_factor<T: PrimInt + Unsigned + Roots>(n: T) -> Vec<T> {
67    let mut factors: Vec<T> = Vec::new();
68
69    let zero = T::zero();
70    let one = T::one();
71    let two = one + one;
72
73    if n < two {
74        return factors;
75    }
76
77    factors.push(one);
78    let root_n = n.sqrt();
79
80    let mut factor = two;
81    while factor <= root_n {
82        if n % factor == zero {
83            factors.push(factor);
84        }
85        factor = factor + one;
86    }
87    let is_square = root_n * root_n == n;
88    let mid = factors.len();
89    for index in (1..mid).rev() {
90        let factor = factors[index];
91        if !(is_square && factor == root_n) {
92            factors.push(n / factor);
93        }
94    }
95    factors
96}
97
98/// For all unsigned integer inputs, returns all factors of the number, excluding one and the number
99/// itself.
100///
101/// # Examples
102///
103/// ```
104/// assert_eq!(fast_factor::exclusive_factor(0_u32), vec![]);
105/// assert_eq!(fast_factor::exclusive_factor(1_u32), vec![]);
106/// assert_eq!(fast_factor::exclusive_factor(7_u32), vec![]);
107/// assert_eq!(fast_factor::exclusive_factor(12_u32), vec![2,3,4,6]);
108/// assert_eq!(fast_factor::exclusive_factor(36_u32), vec![2,3,4,6,9,12,18]);
109/// ```
110pub fn exclusive_factor<T: PrimInt + Unsigned + Roots>(n: T) -> Vec<T> {
111    let mut factors: Vec<T> = Vec::new();
112
113    let zero = T::zero();
114    let one = T::one();
115    let two = one + one;
116
117    if n < two + two {
118        return factors;
119    }
120
121    let root_n = n.sqrt();
122
123    let mut factor = two;
124    while factor <= root_n {
125        if n % factor == zero {
126            factors.push(factor);
127        }
128        factor = factor + one;
129    }
130    let is_square = root_n * root_n == n;
131    let mid = factors.len();
132    for index in (0..mid).rev() {
133        let factor = factors[index];
134        if !(is_square && factor == root_n) {
135            factors.push(n / factor);
136        }
137    }
138    factors
139}