Reputation: 458
I am trying to calculate the number of combinations of the number of elements in a certain array. I need the exact number of combinations to use it as number of threads to be executed in the GPU.
But the data is very big and the factorial can't be calculated for that big a number with any data type.
Is there a way to calculate the number of combinations without having to find the factorial? Or a more efficient way to do so?
It summarizes the problem:
int no_of_combinations = combination(500,2);
public static int factorial(int m)
{
int x = 1;
for (int i = m; i > 0; i--)
x = x * i;
return x;
}
public static int combination(int m, int n)
{
int x = 0;
x = factorial(m) / (factorial(n) * factorial(m - n));
return x;
}
Upvotes: 1
Views: 1151
Reputation: 3316
You don't need to use factorials. If k>n/2, then use C(n,k)=C(n,n-k). Then use that C(n,0)=1 and for k>0, C(n,k) = C(n,k-1) * (n-k+1)/k. This lets you compute almost as many binomial coefficients as the dynamic programming method but it takes linear time (Theta(min(n-k,k))) and constant space instead of quadratic time and linear space.
See this past question: How to efficiently calculate a row in pascal's triangle?
public static long combination(int n, int k)
{
if (n-k < k)
return combination(n,n-k);
if (k < 0)
return 0;
long result = 1;
for (int i=1; i<=k; i++)
{
result *= n-i+1;
result /=i;
}
return result;
}
This may overflow if the answer times n exceeds the maximum long. So, if you expect the answer to fit in a 32 bit int and you have 64 bit longs, then this should not overflow. To avoid overflowing, use BigIntegers instead of longs.
Upvotes: 2
Reputation: 244
You need to write a new function, lets call it FactorialMoverN
int FactorialMOverN(int m, int n)
{
int x = 1;
for (int i = m; i > n; i--)
x = x * i;
return x;
}
Then change your combination function to
x = FactorialMOverN(m,n) * factorial(m - n));
This should help. If it doesn't help, then you need to use a different variable type, or rethink your problem.
Thanks to Sami, I can see that the above function is in error. The 500 choose 2 needs to be calculated via
int MChooseN(int m, int n)
{
int x = 1;
for (int i = m; i > (m-n); i--)
x = x * i;
return x;
}
The above will take 500, 2 and return 500*499, the previous would have taken 500,2 and returned 500*499*498...5*4*3 which is not what you wanted.
Anyway, the above is the best you can get.
Upvotes: 0
Reputation: 31143
In this case I would start to simplify the equation. In your example you're looking for 500 choose 2, which is 500!/498!/2!. This can be easily changed to 500*499/2, which can be calculated.
In general terms if you have n choose k, you only need to calculate a "partial factorial" from n to max(k, n-k) and then divide by min(k, n-k)! due to the results being mirrored. This makes the calculation much easier.
Also in certain cases you could start dividing with the min(k, n-k)! while multiplying, but that will lead to remainders etc.
Upvotes: 4
Reputation: 46943
Use the Pascal's triangle property:
C(n,k) = C(n - 1, k) + C(n - 1, k - 1) and dynamic programming. No factorials involved.
The triangle of Pascal being:
1 1 1 1 2 1 1 3 3 1 1 4 6 4 1
Upvotes: 3