pub trait Divisors: Sized {
fn divisors_unordered(&self) -> Vec<Self>;
fn divisors(&self) -> Vec<Self>
where
Self: Ord,
{
let mut v = self.divisors_unordered();
v.sort_unstable();
v
}
}
macro_rules! impl_divisors {
($t:ty) => {
impl Divisors for $t {
fn divisors_unordered(&self) -> Vec<Self> {
#[inline]
fn repeat_division(mut n: $t, d: $t) -> ($t, usize) {
for rep in 0.. {
let (new_n, rem) = (n / d, n % d);
if rem != 0 {
return (n, rep);
}
n = new_n;
}
unreachable!();
}
#[inline]
fn multiply_and_extend(v: &mut Vec<$t>, multiplier: $t, rep: usize) {
v.reserve(v.len() * (rep + 1));
for i in 0..v.len() * rep {
let vi = unsafe { v.get_unchecked(i) };
v.push(vi * multiplier);
}
}
#[inline]
fn candidates() -> impl Iterator<Item = $t> {
[2, 3, 5].into_iter().chain(
(7..).step_by(30).flat_map(|d| {
[d, d + 4, d + 6, d + 10, d + 12, d + 16, d + 22, d + 24]
}),
)
}
if *self == 0 {
return vec![];
}
let mut divisors = vec![1];
let mut n = *self;
for d in candidates() {
if !d.checked_mul(d).is_some_and(|res| res <= n) {
break;
}
let (new_n, rep) = repeat_division(n, d);
n = new_n;
multiply_and_extend(&mut divisors, d, rep);
}
if n > 1 {
multiply_and_extend(&mut divisors, n, 1);
}
divisors
}
}
};
}
impl_divisors!(u8);
impl_divisors!(u16);
impl_divisors!(u32);
impl_divisors!(u64);
impl_divisors!(u128);
impl_divisors!(usize);
#[cfg(test)]
mod test {
use crate::Divisors;
fn do_test(n: u32) {
assert_eq!(n.divisors(), get_divisors_standard(n));
}
#[test]
fn test_smallest() {
for i in 0..10 {
do_test(i);
}
}
#[test]
fn test_small() {
for i in 10..100000 {
do_test(i);
}
}
#[test]
fn test_near_max() {
for i in u32::MAX - 1000..=u32::MAX {
do_test(i);
}
}
fn get_divisors_standard(n: u32) -> Vec<u32> {
let mut v = Vec::new();
let n_sqrt = (n as f32).sqrt() as u32 + 1;
for i in 1..n_sqrt {
if n % i == 0 {
if n / i == i {
v.push(i);
} else {
v.push(i);
v.push(n / i);
}
}
}
v.sort();
v
}
}