Even after taking into account Cherubim Anand's good answer, you can still make facts
faster using a better algorithm based on mathematical properties like:
$$if n = \prod_{i=1}^r p_i^{a_i}, facts(n)=\prod_{i=1}^r (a_i+1).$$
Thus, iterating over number to identify prime factors and their exponents, you can easily determine the number of factors.
int facts3(int n)
{
if (n <= 2)
return n;
int facts = 1;
for (int d = 2; d * d <= n; d++)
{
int pow = 0;
nb_mod_facts3++;
while (n % d == 0)
{
n /= d;
pow++;
}
facts *= (pow + 1);
}
if (n > 1) // remaining prime factor (with exp 1)
{
int pow = 1;
facts *= (pow + 1);
}
return facts;
}
Some more improvement (visible below) could be used (make d
go though 2
and then only odd values) but the major point is to use the formula above.
Benchmark:
I've used the following code to ensure that the different functions lead to similar results (after some minor adjustment) and to evaluate the performances by counting the number of modulo operations.
#include <stdio.h>
int nb_mod_facts1 = 0;
int nb_mod_facts2 = 0;
int nb_mod_facts3 = 0;
int nb_mod_facts4 = 0;
int facts(int h)
{
int factors=0;
for(int k=1; k<=h; k++)
{
nb_mod_facts1++;
if((h%k)==0)
{
factors++;
}
}
return factors;
}
int facts2(int n)
{
if (n <= 2)
return n;
int factors = 2; //as 1 and number itself are already considered as factors
for(int k=2; k<=(n/2); k++)
{
nb_mod_facts2++;
if((n%k)==0)
{
factors++;
}
}
return factors;
}
int facts3(int n)
{
if (n <= 2)
return n;
int facts = 1;
for (int d = 2; d * d <= n; d++)
{
int pow = 0;
nb_mod_facts3++;
while (n % d == 0)
{
n /= d;
pow++;
nb_mod_facts3++;
}
facts *= (pow + 1);
}
if (n > 1) // remaining prime factor (with exp 1)
{
int pow = 1;
facts *= (pow + 1);
}
return facts;
}
int facts4(int n)
{
if (n <= 2)
return n;
int facts = 1;
// Consider 2 as special
{
int d = 2;
int pow = 0;
nb_mod_facts4++;
while (n % d == 0)
{
n /= d;
pow++;
nb_mod_facts4++;
}
facts *= (pow + 1);
}
for (int d = 3; d * d <= n; d+=2)
{
int pow = 0;
nb_mod_facts4++;
while (n % d == 0)
{
n /= d;
pow++;
nb_mod_facts4++;
}
facts *= (pow + 1);
}
if (n > 1) // remaining prime factor (with exp 1)
{
int pow = 1;
facts *= (pow + 1);
}
return facts;
}
int main(int argc, char* argv[])
{
for (int i = 0; i < 29999; i++)
{
int f1 = facts(i);
int f2 = facts2(i);
int f3 = facts3(i);
int f4 = facts4(i);
if (f1 != f2)
printf("Something wrong for i=%d : f1:%d != f2:%d\n", i, f1, f2);
if (f1 != f3)
printf("Something wrong for i=%d : f1:%d != f3:%d\n", i, f1, f3);
if (f1 != f4)
printf("Something wrong for i=%d : f1:%d != f4:%d\n", i, f1, f4);
}
printf("Number of modulo operations : %d %d %d %d\n", nb_mod_facts1, nb_mod_facts2, nb_mod_facts3, nb_mod_facts4);
printf("Speed factor : %d %d %d %d\n", nb_mod_facts1/nb_mod_facts1, nb_mod_facts1/nb_mod_facts2, nb_mod_facts1/nb_mod_facts3, nb_mod_facts1/nb_mod_facts4);
return 0;
}
The results are the following :
Number of modulo operations : 449955001 224940004 1287262 703821
Speed factor : 1 2 349 639
Also please note that facts
may not be the best name as I may lead to confusion with factorial often being called fact
.