1

to find factors of number, i am using function void primeFactors(int n)

# include <stdio.h>
# include <math.h>
# include <iostream>
# include <map>

using namespace std; 
// A function to print all prime factors of a given number n
map<int,int> m;
void primeFactors(int n)
{
    // Print the number of 2s that divide n
    while (n%2 == 0)
    {
        printf("%d ", 2);
        m[2] += 1;
        n = n/2;
    }

    // n must be odd at this point.  So we can skip one element (Note i = i +2)
    for (int i = 3; i <= sqrt(n); i = i+2)
    {
        // While i divides n, print i and divide n
        while (n%i == 0)
        {
            int k = i;
            printf("%d ", i);
            m[k] += 1; 
            n = n/i;
        }
    }

    // This condition is to handle the case whien n is a prime number
    // greater than 2
    if (n > 2)
        m[n] += 1; 
        printf ("%d ", n);


   cout << endl;
}

/* Driver program to test above function */
int main()
{
    int n = 72;
    primeFactors(n);
    map<int,int>::iterator it;
    int to = 1;
    for(it = m.begin(); it != m.end(); ++it){
        cout << it->first << " appeared " << it->second << " times "<< endl;
        to *= (it->second+1);
    }
    cout << to << " total facts" << endl;
    return 0;
}

You can check it here. Test case n = 72. http://ideone.com/kaabO0

How do I solve above problem using above algo. (Can it be optimized more ?). I have to consider large numbers as well.

What I want to do .. Take example for N = 864, we found X = 72 as (72 * 12 (no. of factors)) = 864)

Mohit Kumar
  • 500
  • 6
  • 24
  • Could you give an example of what you are looking for? E.g., if `x = 12`, then the number of unique factors is `6` (1, 2, 3, 4, 6, 12), and `n = 12 * 6 = 72`? Or do you want to count prime factors (`2 * 2 * 3`), in which case `n = 12 * 3 = 36`? – Holt Nov 29 '16 at 07:40
  • What do you mean by large numbers? Can you tell the range of N? – vish4071 Nov 29 '16 at 09:24
  • [Why is “using namespace std” considered bad practice?](http://stackoverflow.com/q/1452721/995714). And you should include [`` and ``](http://stackoverflow.com/q/15656434/995714) instead of `stdio.h` and `math.h` – phuclv Nov 30 '16 at 03:33

3 Answers3

1

There is a prime-factorizing algorithm for big numbers, but actually it is not often used in programming contests.
I explain 3 methods and you can implementate using this algorithm.
If you implementated, I suggest to solve this problem.
Note: In this answer, I use integer Q for the number of queries.

O(Q * sqrt(N)) solution per query
Your algorithm's time complexity is O(n^0.5).
But you are implementating with int (32-bit), so you can use long long integers.
Here's my implementation: http://ideone.com/gkGkkP

O(sqrt(maxn) * log(log(maxn)) + Q * sqrt(maxn) / log(maxn)) algorithm
You can reduce the number of loops because composite numbers are not neccesary for integer i.
So, you can only use prime numbers in the loop.

Algorithm:

  1. Calculate all prime numbers <= sqrt(n) with Eratosthenes's sieve. The time complexity is O(sqrt(maxn) * log(log(maxn))).
  2. In a query, loop for i (i <= sqrt(n) and i is a prime number). The valid integer i is about sqrt(n) / log(n) with prime number theorem, so the time complexity is O(sqrt(n) / log(n)) per query.

More efficient algorithm
There are more efficient algorithm in the world, but it is not used often in programming contests.
If you check "Integer factorization algorithm" on the internet or wikipedia, you can find the algorithm like Pollard's-rho or General number field sieve.

square1001
  • 1,402
  • 11
  • 26
1

My best shot at performance without getting overboard with special algos.

The Erathostenes' seive - the complexity of the below is O(N*log(log(N))) - because the inner j loop starts from i*i instead of i.

#include <vector>
using std::vector;

void erathostenes_sieve(size_t upToN, vector<size_t>& primes) {
  primes.clear();
  vector<bool> bitset(upToN+1, true); // if the bitset[i] is true, the i is prime
  bitset[0]=bitset[1]=0;

  // if i is 2, will jump to 3, otherwise will jump on odd numbers only
  for(size_t i=2; i<=upToN; i+=( (i&1) ? 2 : 1)) {
    if(bitset[i]) { // i is prime
      primes.push_back(i);
      // it is enough to start the next cycle from i*i, because all the 
      // other primality tests below it are already performed:
      // e.g:
      // - i*(i-1) was surely marked non-prime when we considered multiples of 2
      // - i*(i-2) was tested at (i-2) if (i-2) was prime or earlier (if non-prime)
      for(size_t j=i*i; j<upToN; j+=i) {
         bitset[j]=false; // all multiples of the prime with value of i
                          // are marked non-prime, using **addition only**
      }
    }
  }
}

Now factoring based on the primes (set in a sorted vector). Before this, let's examine the myth of sqrt being expensive but a large bunch of multiplications is not.

First of all, let us note that sqrt is not that expensive anymore: on older CPU-es (x86/32b) it used to be twice as expensive as a division (and a modulo operation is division), on newer architectures the CPU costs are equal. Since factorisation is all about % operations again and again, one may still consider sqrt now and then (e.g. if and when using it saves CPU time).

For example consider the following code for an N=65537 (which is the 6553-th prime) assuming the primes has 10000 entries

size_t limit=std::sqrt(N);
size_t largestPrimeGoodForN=std::distance(
  primes.begin(), 
  std::upper_limit(primes.begin(), primes.end(), limit) // binary search
);
// go descendingly from limit!!!
for(int i=largestPrimeGoodForN; i>=0; i--) { 
   // factorisation loop
}

We have:

  • 1 sqrt (equal 1 modulo),
  • 1 search in 10000 entries - at max 14 steps, each involving 1 comparison, 1 right-shift division-by-2 and 1 increment/decrement - so let's say a cost equal with 14-20 multiplications (if ever)
  • 1 difference because of std::distance.

So, maximal cost - 1 div and 20 muls? I'm generous.

On the other side:

for(int i=0; primes[i]*primes[i]<N; i++) {
  // factorisation code
}

Looks much simpler, but as N=65537 is prime, we'll go through all the cycle up to i=64 (where we'll find the first prime which cause the cycle to break) - a total of 65 multiplications.
Try this with a a higher prime number and I guarantee you the cost of 1 sqrt+1binary search are better use of the CPU cycle than all the multiplications on the way in the simpler form of the cycle touted as a better performance solution


So, back to factorisation code:

#include <algorithm>
#include <math>
#include <unordered_map>
void factor(size_t N, std::unordered_map<size_t, size_t>& factorsWithMultiplicity) {
      factorsWithMultiplicity.clear();

   while( !(N & 1) ) { // while N is even, cheaper test than a '% 2'
     factorsWithMultiplicity[2]++;
     N = N >> 1; // div by 2 of an unsigned number, cheaper than the actual /2
   }
   // now that we know N is even, we start using the primes from the sieve
   size_t limit=std::sqrt(N); // sqrt is no longer *that* expensive,

   vector<size_t> primes;
   // fill the primes up to the limit. Let's be generous, add 1 to it
   erathostenes_sieve(limit+1, primes);
   // we know that the largest prime worth checking is
   // the last element of the primes.
   for(
     size_t largestPrimeIndexGoodForN=primes.size()-1;
     largestPrimeIndexGoodForN<primes.size(); // size_t is unsigned, so after zero will underflow
     // we'll handle the cycle index inside
   ) {
     bool wasFactor=false;
     size_t factorToTest=primes[largestPrimeIndexGoodForN];
     while( !( N % factorToTest) ) {
       wasFactor=true;// found one
       factorsWithMultiplicity[factorToTest]++;
       N /= factorToTest;
     }
     if(1==N) { // done
        break;
     }
     if(wasFactor) { // time to resynchronize the index
       limit=std::sqrt(N);
       largestPrimeIndexGoodForN=std::distance(
          primes.begin(),
          std::upper_bound(primes.begin(), primes.end(), limit)
       );
     }
     else { // no luck this time
       largestPrimeIndexGoodForN--;
     }
   } // done the factoring cycle
   if(N>1) { // N was prime to begin with
     factorsWithMultiplicity[N]++;
   }
}
Community
  • 1
  • 1
Adrian Colomitchi
  • 3,974
  • 1
  • 14
  • 23
1

Well,I will show you the code.

# include <stdio.h>
# include <iostream>
# include <map>
using namespace std;
const long MAX_NUM = 2000000;
long prime[MAX_NUM] = {0}, primeCount = 0;
bool isNotPrime[MAX_NUM] = {1, 1}; // yes. can be improve, but it is useless when sieveOfEratosthenes is end
void sieveOfEratosthenes() {
    //@see https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
    for (long i = 2; i < MAX_NUM; i++) { // it must be i++
        if (!isNotPrime[i]) //if it is prime,put it into prime[]
            prime[primeCount++] = i;
        for (long j = 0; j < primeCount && i * prime[j] < MAX_NUM; j++) { /*foreach prime[]*/
//            if(i * prime[j] >= MAX_NUM){ // if large than MAX_NUM break
//                break;
//            }
            isNotPrime[i * prime[j]] = 1;  // set i * prime[j] not a prime.as you see, i * prime[j]
            if (!(i % prime[j])) //if this prime the min factor of i,than break.
                                 // and it is the answer why not i+=( (i & 1) ? 2 : 1).
                                 // hint : when we judge 2,prime[]={2},we set 2*2=4 not prime
                                 //        when we judge 3,prime[]={2,3},we set 3*2=6 3*3=9 not prime
                                 //        when we judge 4,prime[]={2,3},we set 4*2=8 not prime (why not set 4*3=12?)
                                 //        when we judge 5,prime[]={2,3,5},we set 5*2=10 5*3=15 5*5=25 not prime
                                 //        when we judge 6,prime[]={2,3,5},we set 6*2=12 not prime,than we can stop
                                 // why not put 6*3=18 6*5=30 not prime? 18=9*2 30=15*2.
                                 // this code can make each num be set only once,I hope it can help you to understand
                                 // this is difficult to understand but very useful.
                break;
        }
    }
}
void primeFactors(long n)
{
    map<int,int> m;
    map<int,int>::iterator it;
    for (int i = 0; prime[i] <= n; i++) // we test all prime small than n , like 2 3 5 7... it musut be i++
    {
        while (n%prime[i] == 0)
        {
            cout<<prime[i]<<" ";
            m[prime[i]] += 1;
            n = n/prime[i];
        }
    }
    cout<<endl;
    int to = 1;
    for(it = m.begin(); it != m.end(); ++it){
        cout << it->first << " appeared " << it->second << " times "<< endl;
        to *= (it->second+1);
    }
    cout << to << " total facts" << endl;

}
int main()
{
    //first init for calculate all prime numbers,for example we define MAX_NUM = 2000000
    // the result of prime[] should be stored, you primeFactors will use it
    sieveOfEratosthenes();
    //second loop for i (i*i <= n and i is a prime number). n<=MAX_NUM
    int n = 72;
    primeFactors(n);
    n = 864;
    primeFactors(n);
    return 0;
}
StyleTang
  • 23
  • 7
  • "bool isNotPrime[MAX_NUM]" - (groan) - have mercy... and use a `std::vector` for the purpose, has a space requirement 8 times smaller than an array of `bool`s. As you may want to climb high on the max number, the space complexity start to matter (cpu cache locality, the fact that primes become rare as you climb in their value and what not). – Adrian Colomitchi Nov 29 '16 at 15:39
  • `for (long i = 2; i < MAX_NUM; i++)` - (double groan). Why `i++`? Why not `i+=( (i & 1) ? 2 : 1)`. Explanation: when `i==2` (the first pass through the cycle), you increment `i` by 1. The next passes, you go with a step of 2. (the same goes for `for (int i = 0; prime[i]*prime[i] <= n; i ++)`) – Adrian Colomitchi Nov 29 '16 at 15:45
  • `for (long j = 0; j < primeCount && i * prime[j] < MAX_NUM; j++) ...` in the sieve... Oh, come on, mate, really. What's wrong with `for(long j = i*i; j – Adrian Colomitchi Nov 29 '16 at 16:07
  • @AdrianColomitchi prime[i]*prime[i] <= n is a bug. and I fixed it to prime[i] <= n – StyleTang Nov 30 '16 at 02:40
  • @AdrianColomitchi I have put some remark in the code.or you can wirite the code yourself and debug it.I hope it can answer you question :) – StyleTang Nov 30 '16 at 03:16
  • "you can wirite the code yourself" So I did, but not with your code. Maybe you'll find something interesting in my answer - e.g. the cost of a `sqrt` used in the correct place may be smaller than the cost of repeated multiplications (as in `primes[i]*primes[i] < N`) – Adrian Colomitchi Nov 30 '16 at 07:58