Computing All Integer Factors in Ascending Order with Rust

A straightforward Rust implementation for finding all factors of a number is shown below. This approach iterates up to the square root of the input value.

fn compute_factors_simple(num: u64) -> Vec<u64> {
    let sqrt_val = (num as f64).sqrt().floor() as u64;
    let mut factors = Vec::new();
    for divisor in 1..=sqrt_val {
        if num % divisor == 0 {
            factors.push(divisor);
            if divisor * divisor != num {
                factors.push(num / divisor);
            }
        }
    }
    factors
}

This algorithm operates in (O(\sqrt{n})) time complexity.

An alternative method first decomposes the number into its prime factors. It then uses a BTreeMap to generate all factors in ascending order. The process starts with 1 and systematically multiplies by prime factors.

fn compute_factors_advanced(mut num: u64) -> Vec<u64> {
    use std::collections::BTreeMap;
    let sqrt_bound = (num as f64).sqrt().floor() as u64;
    let mut prime_counts: Vec<(u64, u32)> = Vec::new();
    
    for prime_candidate in 2..=sqrt_bound {
        if prime_candidate > num { break; }
        while num % prime_candidate == 0 {
            num /= prime_candidate;
            match prime_counts.last_mut() {
                Some(last) if last.0 == prime_candidate => last.1 += 1,
                _ => prime_counts.push((prime_candidate, 1)),
            }
        }
    }
    if num != 1 {
        prime_counts.push((num, 1));
    }

    let zero_exponents = vec![0; prime_counts.len()];
    let mut factor_tree: BTreeMap<u64, Vec<u32>> = BTreeMap::new();
    factor_tree.insert(1, zero_exponents);
    
    let mut result_factors = Vec::new();
    while let Some((current_factor, exponents)) = factor_tree.pop_first() {
        result_factors.push(current_factor);
        for (idx, &(prime, max_exp)) in prime_counts.iter().enumerate() {
            if exponents[idx] < max_exp {
                let mut new_exponents = exponents.clone();
                new_exponents[idx] += 1;
                factor_tree.insert(current_factor * prime, new_exponents);
            }
        }
    }
    result_factors
}

The prime factorization step has a best-case complexity of (O(\log n)) and a worst-case of (O(\sqrt{n})) when the input is prime. BTreeMap operations (insertion, deletion) are (O(\log k)) where (k) is the number of elements. A BinaryHeap is unsuitable here because it permits duplicate entries, wich would produce incorrect factors.

The average number of distinct prime factors for a number is proportional to (\log n). In the best case, factorization is (O(\log n)), and each factor generation step involves (O(\log n)) operations. The total number of factors for a number is roughly (O(n^{1/3})), leading to an estimated average time complexity of (O(n^{1/3} (\log n)^2)). The worst-case remains (O(\sqrt{n})).

Performance testing with 100 random u64 integers reveals that the advanced method can be slower for numbers with simple factorizations due to copying overhead. However, for numbers with high multiplicities in their prime factors (e.g., (2^{10} \cdot 11^{5})), it can be significantly faster. Using a precomputed prime table could improve speed but increases memory usage.

Tags: rust algorithms number-theory factors Optimization

Posted on Tue, 28 Jul 2026 16:25:21 +0000 by pazzy