#include <stdio.h>
int main(){
int n, v;
printf("Please enter a value from 39 to 59: \n");
scanf("%d", &n);
printf("Please enter a value from 3 to 7: \n");
scanf("%d", &v);
}
当我从用户那里获得这些值时,我该如何进行这种因子计算:
n! / ((n-v)! * v!))
我尝试过不同的数据类型,但显然没有人可以保留结果。
例如:n = 49,v = 6。结果是:13,983,816,但我怎么能得到它呢?
答案 0 :(得分:5)
你最好的办法是抛弃天真的阶乘实现,通常是基于递归,然后切换到返回伽玛函数的自然对数的实现。
伽玛函数与阶乘有关:gamma(n) = (n-1)!
最重要的是natural log of gamma,因为你可以像这样重写那个表达式:
ln(n!/(n-v)!v!) = ln(n!) - ln((n-v)!) - ln(v!)
但是
(n-v)! = gamma(n-v+1)
n! = gamma(n+1)
v! = gamma(v+1)
所以
ln(n!/(n-v)!v!) = lngamma(n+1) - lngamma(n-v+1) - lngamma(v+1)
您可以在Numerical Recipes中找到lngamma
的实现。
lngamma
会返回一个双精度数,因此它甚至适用于较大的值。
不言而喻,您将双方exp()
获取您想要的原始表达。
答案 1 :(得分:3)
@duffymo想法看起来太有趣了:从lgamma()
使用<math.h>
。
过去的结果可能是x=1e15
,开始失去有效的有效数字。能够获得1000000.0!
仍然很有趣。
void factorial_expo(double x, double *significand, double *expo) {
double y = lgamma(x+1);
const static double ln10 = 2.3025850929940456840179914546844;
y /= ln10;
double ipart;
double fpart = modf(y, &ipart);
if (significand) *significand = pow(10.0, fpart);
if (expo) *expo = ipart;
}
void facttest(double x) {
printf("%.1f! = ", x);
double significand, expo;
factorial_expo(x, &significand, &expo);
int digits = expo > 15 ? 15 : expo;
if (digits < 1) digits++;
printf("%.*fe%.0f\n", digits, significand, expo);
}
int main(void) {
facttest(0.0);
facttest(1.0);
facttest(2.0);
facttest(6.0);
facttest(10.0);
facttest(69.0);
facttest(1000000.0);
return 0;
}
0.0! = 1.0e0
1.0! = 1.0e0
2.0! = 2.0e0
6.0! = 7.20e2
10.0! = 3.628800e6
69.0! = 1.711224524281441e98
1000000.0! = 8.263931668544735e5565708
答案 2 :(得分:2)
在评论中,您最后说您不需要确切的结果。
只需使用浮点数。您需要处理的最大中间结果是59!
,大约是1.3868e80
;类型double
足以容纳该值。
编写如下函数:
double factorial(int n);
(我认为你知道如何实现它)并使用它。
如果您要进行大量的这些计算,您可能希望通过将结果存储在数组中来缓存结果。如果您定义如下数组:
double fact[60];
然后您可以将N!
的值存储在fact[N]
中,以便N从0到59,并且您可以在大约计算59!
所需的时间内填充整个数组就一次。否则,你将在每次计算时进行几十次浮点乘法和除法 - 如果你这样做一次是微不足道的,但如果你这样做,可能会很重要,比如数千或数百万次。
如果您需要精确的结果,您可以使用像GNU MP这样的扩展整数库,正如其他人所建议的那样。或者您可以使用内置支持任意长度整数的语言(例如Python)。
或者你可以按照避免溢出的顺序执行乘法和除法;我不知道该怎么做,但由于n! / ((n-v)! * v!))
是一个常见的公式,我强烈怀疑已经完成了工作。
答案 3 :(得分:0)
您无法以简单的方式使用59!
这么长的数字。
但是,您可以使用特殊的C
库,这些库使用大于8字节的长数字,例如GMP