65

According to this post, we can get all divisors of a number through the following codes.

for (int i = 1; i <= num; ++i){
    if (num % i == 0)
        cout << i << endl;
}

For example, the divisors of number 24 are 1 2 3 4 6 8 12 24.

After searching some related posts, I did not find any good solutions. Is there any efficient way to accomplish this?

My solution:

  1. Find all prime factors of the given number through this solution.
  2. Get all possible combinations of those prime factors.

However, it doesn't seem to be a good one.

Community
  • 1
  • 1
zangw
  • 43,869
  • 19
  • 177
  • 214
  • 11
    What do you think is "not good" about your proposed prime number approach? Off the top of my head it sounds like the most feasible approach for large numbers. Factorising is known to be a "hard" (i.e. slow) problem. Much of the world depends on this fact. Do you know the maximum size of input you would expect? A less general approach might be to precalculate a table of primes suitable for the input range, and use that. – BoBTFish Nov 05 '14 at 09:49
  • 1
    I think `get all possible combinations of those prime factors` can not be efficient. – zangw Nov 05 '14 at 09:57
  • It may be better on average to get only the prime factors and then generate the combinations. That doesn't help if the original number is prime, but if it isn't then you'll do far fewer divisions. – harold Nov 05 '14 at 09:58
  • Why not? Put it this way: with a generative approach, you deal with just the actual factors. With an iterative approach, you have to deal with vastly more numbers that are **not** factors, even if discounting them is quick. Not doing the analysis, but I would assume that is quicker, even if the process of generating combinations is slow. For large numbers, the amount of potential factors you have to deal with is going to grow fast enough to outweigh the more expensive combination computation. Disclaimer: I am guessing, not calculating. – BoBTFish Nov 05 '14 at 10:04
  • And if the inputs are very large, it would probably be prudent to run it through a prime check first (e.g. google Rabin-Miller). But this may be overkill for the scope of what you are doing. – BoBTFish Nov 05 '14 at 10:05
  • @BoBTFish, you are right. I am also guessing my idea is not efficient. – zangw Nov 05 '14 at 10:09
  • 10
    @zangw "*I think get all possible combinations of those prime factors can not be efficient.*" Huh? Compared to finding the factors in the first place, that's absolutely trivial -- it's basically just counting. – David Schwartz Nov 05 '14 at 10:12
  • @zangw By "efficient", do you mean "code is easy to write"? If yes, see the answer by Yu Hao. – anatolyg Nov 05 '14 at 13:13
  • @anatolyg, sort of, also I want to implement it with less time complexity. – zangw Nov 05 '14 at 13:16
  • If you just happen to be looking for perfect numbers, then there's a much more efficient way of doing it. – barak manos Nov 05 '14 at 15:07
  • @zangw "get all possible combinations of those prime factors" is trivial. See my answer below. Writing maths in comments is too hard. – phil_20686 Nov 05 '14 at 15:24

15 Answers15

98

Factors are paired. 1 and 24, 2 and 12, 3 and 8, 4 and 6.

An improvement of your algorithm could be to iterate to the square root of num instead of all the way to num, and then calculate the paired factors using num / i.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • 1
    Also, since you only care about the whole part of the square root, you can use a simple square-root algorithm. – Keen Nov 05 '14 at 18:33
  • 8
    If this is a repeated algorithm, i.e. want to find the divisors of lots of numbers, generating all the primes up to root(n) with a sieve and then generating the prime decomposition, and iterating over it to get all the factors, will be much faster. This is because primes are logarithmically distributed, so large primes tend to be far apart. So you have far fewer divisions. – phil_20686 Nov 07 '14 at 10:49
  • @phil_20686, what you mentioned is it a dynamic programming based approach? – taurus05 Feb 23 '19 at 18:03
  • 2
    you can also save on square root by doing `for (int i = 1; i * i <= num; i++)` – Abhishek Choudhary Nov 03 '21 at 07:15
  • @AbhishekChoudhary That's incorrect. You can avoid the square root using `for (int i = 1; (i + 1) * (i + 1) <= num; i++)`. Your formula misses out on e.g. `num = 90`. It does have a divisor of `10` but `i = 10` will break the loop. – l33t Apr 07 '23 at 21:34
  • 1
    @l33t No, it's correct, by your logic it also misses 45, 10 is already counted by 9 as divisor, we have to take both `x` and `num / x` in this method, since 9 * 9 <= 90, we take 9 and 90/9 = 10. – Abhishek Choudhary Apr 08 '23 at 04:26
  • You're right. I forgot about that correlation. – l33t Apr 08 '23 at 20:51
32

You should really check till square root of num as sqrt(num) * sqrt(num) = num:

Something on these lines:

int square_root = (int) sqrt(num) + 1;
for (int i = 1; i < square_root; i++) { 
    if (num % i == 0&&i*i!=num)
        cout << i << num/i << endl;
    if (num % i == 0&&i*i==num)
        cout << i << '\n';
}
SMA
  • 36,381
  • 8
  • 49
  • 73
  • 5
    There's no reason to do that. Any C compiler with optimizations turned on will do that (Clang does it for any optimization level higher than 0, for example). I would be more worried about the unmatched paren on the first line. – Aaron Dufour Nov 05 '14 at 17:06
18

There is no efficient way in the sense of algorithmic complexity (an algorithm with polynomial complexity) known in science by now. So iterating until the square root as already suggested is mostly as good as you can be.

Mainly because of this, a large part of the currently used cryptography is based on the assumption that it is very time consuming to compute a prime factorization of any given integer.

Dennis Jaheruddin
  • 21,208
  • 8
  • 66
  • 122
SpaceTrucker
  • 13,377
  • 6
  • 60
  • 99
11

Here's my code:

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>

using namespace std;

#define pii pair<int, int>

#define MAX 46656
#define LMT 216
#define LEN 4830
#define RNG 100032

unsigned base[MAX / 64], segment[RNG / 64], primes[LEN];

#define sq(x) ((x)*(x))
#define mset(x,v) memset(x,v,sizeof(x))
#define chkC(x,n) (x[n>>6]&(1<<((n>>1)&31)))
#define setC(x,n) (x[n>>6]|=(1<<((n>>1)&31)))

// http://zobayer.blogspot.com/2009/09/segmented-sieve.html
void sieve()
{
    unsigned i, j, k;
    for (i = 3; i<LMT; i += 2)
        if (!chkC(base, i))
            for (j = i*i, k = i << 1; j<MAX; j += k)
                setC(base, j);
    primes[0] = 2;
    for (i = 3, j = 1; i<MAX; i += 2)
        if (!chkC(base, i))
            primes[j++] = i;
}


//http://www.geeksforgeeks.org/print-all-prime-factors-of-a-given-number/
vector <pii> factors;
void primeFactors(int num)
{
    int expo = 0;   
    for (int i = 0; primes[i] <= sqrt(num); i++)
    {
        expo = 0;
        int prime = primes[i];
        while (num % prime == 0){
            expo++;
            num = num / prime;
        }
        if (expo>0)
            factors.push_back(make_pair(prime, expo));
    }

    if ( num >= 2)
        factors.push_back(make_pair(num, 1));

}

vector <int> divisors;
void setDivisors(int n, int i) {
    int j, x, k;
    for (j = i; j<factors.size(); j++) {
        x = factors[j].first * n;
        for (k = 0; k<factors[j].second; k++) {
            divisors.push_back(x);
            setDivisors(x, j + 1);
            x *= factors[j].first;
        }
    }
}

int main() {

    sieve();
    int n, x, i; 
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> x;
        primeFactors(x);
        setDivisors(1, 0);
        divisors.push_back(1);
        sort(divisors.begin(), divisors.end());
        cout << divisors.size() << "\n";
        for (int j = 0; j < divisors.size(); j++) {
            cout << divisors[j] << " "; 
        }
        cout << "\n";
        divisors.clear();
        factors.clear();
    }
}

The first part, sieve() is used to find the prime numbers and put them in primes[] array. Follow the link to find more about that code (bitwise sieve).

The second part primeFactors(x) takes an integer (x) as input and finds out its prime factors and corresponding exponent, and puts them in vector factors[]. For example, primeFactors(12) will populate factors[] in this way:

factors[0].first=2, factors[0].second=2
factors[1].first=3, factors[1].second=1

as 12 = 2^2 * 3^1

The third part setDivisors() recursively calls itself to calculate all the divisors of x, using the vector factors[] and puts them in vector divisors[].

It can calculate divisors of any number which fits in int. Also it is quite fast.

Rocky Johnson
  • 311
  • 3
  • 10
6

Plenty of good solutions exist for finding all the prime factors of not too large numbers. I just wanted to point out, that once you have them, no computation is required to get all the factors.

if N = p_1^{a}*p_{2}^{b}*p_{3}^{c}.....

Then the number of factors is clearly (a+1)(b+1)(c+1).... since every factor can occur zero up to a times.

e.g. 12 = 2^2*3^1 so it has 3*2 = 6 factors. 1,2,3,4,6,12

======

I originally thought that you just wanted the number of distinct factors. But the same logic applies. You just iterate over the set of numbers corresponding to the possible combinations of exponents.

so int he example above:

00
01
10
11
20
21

gives you the 6 factors.

Community
  • 1
  • 1
phil_20686
  • 4,000
  • 21
  • 38
3

If you want all divisors to be printed in sorted order

int i;
for(i=1;i*i<n;i++){             /*print all the divisors from 1(inclusive) to
    if(n%i==0){                   √n (exclusive) */   
        cout<<i<<" ";
    }
}
for( ;i>=1;i--){                /*print all the divisors from √n(inclusive) to
  if(n%i==0){                     n (inclusive)*/   
      cout<<(n/i)<<" ";
  }
}

If divisors can be printed in any order

for(int j=1;j*j<=n;j++){
    if(n%j==0){
        cout<<j<<" ";
        if(j!=(n/j))
           cout<<(n/j)<<" ";
    }
}

Both approaches have complexity O(√n)

Florian Winter
  • 4,750
  • 1
  • 44
  • 69
  • I like the approach to output in ascending order, and the comment on complexity. Please make it a habit to comment&document code: *What is everything* (externally visible) *good for*? – greybeard May 06 '21 at 07:40
  • Thanks a lot for the advice. I will note that. Also, thank you for upvoting my solution. – Amisha Sahu May 06 '21 at 10:25
  • It is returning duplicates, like for 6 it returns `1:2:2:3:6`. – Lance May 03 '22 at 19:15
1

Here is the Java Implementation of this approach:

public static int countAllFactors(int num)
{
    TreeSet<Integer> tree_set = new TreeSet<Integer>();
    for (int i = 1; i * i <= num; i+=1)
    {
        if (num % i == 0)
        {
            tree_set.add(i);
            tree_set.add(num / i);
        }
    }
    System.out.print(tree_set);
    return tree_set.size();
}
Pratik Patil
  • 3,662
  • 3
  • 31
  • 31
0
for( int i = 1; i * i <= num; i++ )
{
/* upto sqrt is because every divisor after sqrt
    is also found when the number is divided by i.
   EXAMPLE like if number is 90 when it is divided by 5
    then you can also see that 90/5 = 18
    where 18 also divides the number.
   But when number is a perfect square
    then num / i == i therefore only i is the factor
*/
greybeard
  • 2,249
  • 8
  • 30
  • 66
mohit rai
  • 11
  • 2
0
//Try this,it can find divisors of verrrrrrrrrry big numbers (pretty efficiently :-))
#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<conio.h>

using namespace std;

vector<double> D;

void divs(double N);
double mod(double &n1, double &n2);
void push(double N);
void show();

int main()
{
    double N; 
    cout << "\n Enter number: "; cin >> N;

    divs(N); // find and push divisors to D

    cout << "\n Divisors of "<<N<<": "; show(); // show contents of D (all divisors of N)

_getch(); // used visual studio, if it isn't supported replace it by "getch();"
return(0);
}

void divs(double N)
{
    for (double i = 1; i <= sqrt(N); ++i)
    {
        if (!mod(N, i)) { push(i); if(i*i!=N) push(N / i); }
    }
}

double mod(double &n1, double &n2)
{
    return(((n1/n2)-floor(n1/n2))*n2);
}

void push(double N)
{
    double s = 1, e = D.size(), m = floor((s + e) / 2);
    while (s <= e)
    {   
        if (N==D[m-1]) { return; }
        else if (N > D[m-1]) { s = m + 1; }
        else { e = m - 1; }
        m = floor((s + e) / 2);
    }
    D.insert(D.begin() + m, N);
}

void show()
{
    for (double i = 0; i < D.size(); ++i) cout << D[i] << " ";
}
Ragib
  • 107
  • 7
0
int result_num;
bool flag;

cout << "Number          Divisors\n";

for (int number = 1; number <= 35; number++)
{
    flag = false;
    cout << setw(3) << number << setw(14);

    for (int i = 1; i <= number; i++) 
    {
        result_num = number % i;

        if (result_num == 0 && flag == true)
        {
            cout << "," << i;
        }

        if (result_num == 0 && flag == false)
        {
            cout << i;
        }

        flag = true;
    }

    cout << endl;   
}
cout << "Press enter to continue.....";
cin.ignore();
return 0;
}
Racil Hilan
  • 24,690
  • 13
  • 50
  • 55
ying
  • 1
0
for (int i = 1; i*i <= num; ++i)
{
    if (num % i == 0)
    cout << i << endl;
    if (num/i!=i)
    cout << num/i << endl;
}
  • 1
    This looks *effective*: executing this has the effect required. However, the question explicitly asks for an `efficient way to accomplish this`: can you please argue how this is a) less work than the approach presented in the question b) simpler than other solutions investing less work, still? How does this answer compare to 40+ other answers? – greybeard Jan 27 '19 at 18:11
  • 1
    (`this has the effect required` - well, almost: lacks a `if (num / i != i) cout << num/i << endl;`.) – greybeard Jan 27 '19 at 18:58
  • In my sense , using i*i and removing the sqrt function makes it faster. – Sifat Ullah Chowdhury Jan 27 '19 at 19:11
  • 1
    By all means: put the arguments *what* makes this a good solution *in your answer* (and not in comments on comments). I misremembered the number of votes for the question as the number of prior answers - my bad, there are only ten of those. Then again, half of them explicitly iterate till *n < i\*i*, only. You could try to get rid of the multiplication too - recall what you know about the series of odd numbers. – greybeard Jan 27 '19 at 21:27
  • Code-only answers are discouraged. Please click on [edit] and add some words summarising how your code addresses the question, or perhaps explain how your answer differs from the previous answer/answers. [From Review](https://stackoverflow.com/review/low-quality-posts/22043678) – Nick Jan 27 '19 at 23:44
0
//DIVISORS IN TIME COMPLEXITY sqrt(n)

#include<bits/stdc++.h>
using namespace std;

#define ll long long

int main()
{
    ll int n;
    cin >> n;

    for(ll i = 2;  i <= sqrt(n); i++)
    {
        if (n%i==0)
        {
            if (n/i!=i)
                cout << i << endl << n/i<< endl;
            else
                cout << i << endl;
        }
    }
}
Das_Geek
  • 2,775
  • 7
  • 20
  • 26
Aditya
  • 13
  • 5
0
#include<bits/stdc++.h> 
using namespace std;
typedef long long int ll;
#define MOD 1000000007
#define fo(i,k,n) for(int i=k;i<=n;++i)
#define endl '\n'
ll etf[1000001];
ll spf[1000001];
void sieve(){
    ll i,j;
    for(i=0;i<=1000000;i++) {etf[i]=i;spf[i]=i;}
    for(i=2;i<=1000000;i++){
        if(etf[i]==i){
            for(j=i;j<=1000000;j+=i){
                etf[j]/=i;
                etf[j]*=(i-1);
                if(spf[j]==j)spf[j]=i;
            }
        }
    }
}
void primefacto(ll n,vector<pair<ll,ll>>& vec){
    ll lastprime = 1,k=0;
    while(n>1){
        if(lastprime!=spf[n])vec.push_back(make_pair(spf[n],0));
        vec[vec.size()-1].second++;
        lastprime=spf[n];
        n/=spf[n];
    }
}
void divisors(vector<pair<ll,ll>>& vec,ll idx,vector<ll>& divs,ll num){
    if(idx==vec.size()){
        divs.push_back(num);
        return;
    }
    for(ll i=0;i<=vec[idx].second;i++){
        divisors(vec,idx+1,divs,num*pow(vec[idx].first,i));
    }
}
void solve(){
    ll n;
    cin>>n;
    vector<pair<ll,ll>> vec;
    primefacto(n,vec);
    vector<ll> divs;
    divisors(vec,0,divs,1);
    for(auto it=divs.begin();it!=divs.end();it++){
        cout<<*it<<endl;
    }
}
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    sieve();
    ll t;cin>>t;
    while(t--) solve();
    return 0;
}
  • Welcome at Stackoverflow. While your answer may help to achieve what the original poster wants, your post offers no guidance or explanation that may help others understand/learn what exactly you are doing and why. Please include more context in your reply, see [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer) – Elijan9 Apr 21 '20 at 11:46
0

We can use modified sieve for getting all the factors for all numbers in range [1, N-1].

for (int i = 1; i < N; i++) {
    for (int j = i; j < N; j += i) {
        ans[j].push_back(i);
    }
}

The time complexity is O(N * log(N)) as the sum of harmonic series 1 + 1/2 + 1/3 + ... + 1/N can be approximated to log(N).

More info about time complexity : https://math.stackexchange.com/a/3367064

P.S : Usually in programming problems, the task will include several queries where each query represents a different number and hence precalculating the divisors for all numbers in a range at once would be beneficial as the lookup takes O(1) time in that case.

Shreyas Shetty
  • 618
  • 6
  • 13
0

java 8 recursive (works on HackerRank). This method includes option to sum and return the factors as an integer.


    static class Calculator implements AdvancedArithmetic {
        public int divisorSum(int n) {
            if (n == 1)
                return 1;

            Set<Integer> set = new HashSet<>();
            return divisorSum( n, set, 1);
        }

        private int divisorSum(int n, Set<Integer> sum, int start){

            if ( start > n/2 )
                return 0;

            if (n%start == 0)
                sum.add(start);

            start++;

            divisorSum(n, sum, start);

            int total = 0;
            for(int number: sum)
                total+=number;
            return total +n;
        }
    }