我编写了一个C ++函数来计算阶乘,并用它来计算 22 C 11 (组合)。我已声明变量ans
并将其设置为0.我试图计算
22C11 = fact(2*n)/(fact(n)*fact(n))
我将n
发送为11.出于某种原因,我在答案中存储了负值。我该如何解决这个问题?
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;
}
主要功能包括以下几行:
long int ans=0;
ans=ans+(fact(2*n)/(fact(n)*fact(n)));
cout<<ans;
我得到的答案是-784 正确的答案应该是705432
注意:此功能在n <= 10时工作正常。我已经尝试了long long int而不是long int但它仍然没有工作。
答案 0 :(得分:3)
实际计算阶乘是不明智的 - 它们增长得非常快。一般来说,使用组合公式,寻找一种重新排序操作的方法是一个好主意,以保持中间结果在某种程度上受到限制。
例如,让我们看一下(2*n)!/(n!*n!)
。它可以重写为((n+1)*(n+2)*...*(2*n)) / (1*2*...*n) == (n+1)/1 * (n+2)/2 * (n+3)/3 ... * (2*n)/n
。通过交叉乘法和除法,中间结果的增长率降低。
所以,像这样:
int f(int n) {
int ret = 1;
for (int i = 1; i <= n; ++i) {
ret *= (n + i);
ret /= i;
}
return ret;
}
答案 1 :(得分:2)
22! = 1,124,000,727,777,607,680,000
2 64 = 18,446,744,073,709,551,615
因此除非你有unsigned long long
的128位整数,否则你会有整数溢出。
答案 2 :(得分:0)
您正在触发整数溢出,这会导致未定义的行为。实际上,您可以使用new JLabel("<html>2 <sup>2</sup>⁄<sub>3</sub></html>")
或long long int
来获得更高的精确度,例如:
unsigned long long int
你说你试过这个并且它没有用,但我猜你忘了也更新了unsigned long long fact(int n)
{
if(n < 2)
return 1;
return fact(n-1) * n;
}
或类似的类型。 (在我的版本中,我删除了x
,因为它是多余的)。和/或你的计算仍然很大,以至于溢出x
。
您可能对this thread感兴趣,{{3}}显示了用于计算不需要这么多中间存储的nCr的算法。
答案 3 :(得分:0)
通过避免蛮力方法,您可以增加成功的机会。
COMB(N1, N2) = FACT(N1)/(FACT(N1-N2)*FACT(N2))
你可以利用这样一个事实,即提名者和分母都有很多共同的术语。
COMB(N1, N2) = (N1-N2+1)*(N1-N2+2)*...*N1/FACT(N1)
这是一个利用该知识并以COMB(22,11)
计算整数溢出风险小得多的实现。
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;
}