C++ function to calculate factorial returns negative value

扶醉桌前 提交于 2019-12-12 04:16:33

问题


I've written a C++ function to calculate factorial and used it to calculate 22C11 (Combination). I have declared a variable ans and set it to 0. I tried to calculate

22C11 = fact(2*n)/(fact(n)*fact(n))

where i sent n as 11. For some reason, i'm getting a negative value stored in answer. How can i fix this?

long int fact(long int n) {
    if(n==1||n==0)
        return 1;
    long int x=1;
    if(n>1)
    x=n*fact(n-1);
    return x;
}

The following lines are included in the main function:

long int ans=0;
    ans=ans+(fact(2*n)/(fact(n)*fact(n)));
cout<<ans;

The answer i'm getting is -784 The correct answer should be 705432

NOTE: This function is working perfectly fine for n<=10. I have tried long long int instead of long int but it still isn't working.


回答1:


It is unwise to actually calculate factorials - they grow extremely fast. Generally, with combinatorial formulae it's a good idea to look for a way to re-order operations to keep intermediate results somewhat constrained.

For example, let's look at (2*n)!/(n!*n!). It can be rewritten as ((n+1)*(n+2)*...*(2*n)) / (1*2*...*n) == (n+1)/1 * (n+2)/2 * (n+3)/3 ... * (2*n)/n. By interleaving multiplication and division, the rate of growth of intermediate result is reduced.

So, something like this:

int f(int n) {
  int ret = 1;
  for (int i = 1; i <= n; ++i) {
    ret *= (n + i);
    ret /= i;
  }
  return ret;
}

Demo




回答2:


22! = 1,124,000,727,777,607,680,000

264 = 18,446,744,073,709,551,615

So unless you have 128-bit integers for unsigned long long you have integer overflow.




回答3:


You are triggering integer overflow, which causes undefined behaviour. You could in fact use long long int, or unsigned long long int to get a little bit more precision, e.g:

unsigned long long fact(int n)
{
    if(n < 2)
        return 1;

    return fact(n-1) * n;
}

You say you tried this and it didn't work but I'm guessing you forgot to also update the type of x or something. (In my version I removed x as it is redundant). And/or your calculation still was so big that it overflowed unsigned long long int.

You may be interested in this thread which shows an algorithm for working out nCr that doesn't require so much intermediate storage.




回答4:


You increasing your chances of success by avoiding the brute force method.

COMB(N1, N2) = FACT(N1)/(FACT(N1-N2)*FACT(N2))

You can take advantage of the fact that both the nominator and the denominator have a lot of common terms.

COMB(N1, N2) = (N1-N2+1)*(N1-N2+2)*...*N1/FACT(N1)

Here's an implementation that makes use of that knowledge and computes COMB(22,11) with much less risk of integer overflow.

unsigned long long comb(int n1, int n2)
{
   unsigned long long res = 1;
   for (int i = (n1-n2)+1; i<= n1; ++i )
   {
      res *= i;
   }

   for (int i = 2; i<= n2; ++i )
   {
      res /= i;
   }

   return res;
}


来源:https://stackoverflow.com/questions/35053226/c-function-to-calculate-factorial-returns-negative-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!