如何编写c ++程序来计算大因子。
例如,如果我想计算(100!)/(99!),我们知道答案是100,但如果我分别计算分子和分母的阶乘,那么这两个数字都是巨大的。
答案 0 :(得分:14)
扩展Dirk的答案(这是正确的答案):
#include "math.h"
#include "stdio.h"
int main(){
printf("%lf\n", (100.0/99.0) * exp(lgamma(100)-lgamma(99)) );
}
尝试它,它确实做你想要的,即使你不熟悉它看起来有点疯狂。使用bigint库将会非常低效。以gammas的日志为例非常快。这会立即运行。
你需要乘以100/99的原因是伽马相当于n-1!不是!所以是的,你可以做exp(lgamma(101)-lgamma(100))而不是。此外,伽玛的定义不仅仅是整数。
答案 1 :(得分:6)
您可以使用Gamma功能,参见the Wikipedia page,它也指向代码。
答案 2 :(得分:5)
当然这个特定的表达式应该被优化,但至于标题问题,我喜欢GMP,因为它提供了一个不错的C ++接口,并且随时可用。
#include <iostream>
#include <gmpxx.h>
mpz_class fact(unsigned int n)
{
mpz_class result(n);
while(n --> 1) result *= n;
return result;
}
int main()
{
mpz_class result = fact(100) / fact(99);
std::cout << result.get_str(10) << std::endl;
}
使用g++ -Wall -Wextra -o test test.cc -lgmpxx -lgmp
答案 3 :(得分:2)
根据您的评论声音,您还需要计算100!/(96!* 4!)等表达式。
“取消了96”,让自己留下(97 * ... * 100)/ 4 !,然后你可以把算术保持在较小的范围内,尽可能少地从“顶部”取数字走。所以,在这种情况下:
i = 96
j = 4
result = i
while (i <= 100) or (j > 1)
if (j > 1) and (result % j == 0)
result /= j
--j
else
result *= i
++i
你当然可以比同样更聪明。
这只会延迟不可避免的事情:最终达到固定尺寸类型的极限。因子爆炸如此迅速,以至于对于重载使用,你将需要多精度。
答案 4 :(得分:1)
以下是如何执行此操作的示例:
http://www.daniweb.com/code/snippet216490.html
他们采取的方法是将大#s存储为数字字符数组。
另见这个问题:Calculate the factorial of an arbitrarily large number, showing all the digits
答案 5 :(得分:1)
您可以使用像gmp这样可以处理任意大整数的大整数库。
答案 6 :(得分:1)
此处可以进行的唯一优化(考虑到m!/n!
m
中的大于n
)意味着在使用乘法之前将所有内容都删掉。
如果m
小于n
,我们必须首先交换元素,然后计算阶乘,然后制作类似1 / result
的内容。请注意,在这种情况下,结果将是double,您应该将其处理为double。
这是代码。
if (m == n) return 1;
// If 'm' is less than 'n' we would have
// to calculate the denominator first and then
// make one division operation
bool need_swap = (m < n);
if (need_swap) std::swap(m, n);
// @note You could also use some BIG integer implementation,
// if your factorial would still be big after crossing some values
// Store the result here
int result = 1;
for (int i = m; i > n; --i) {
result *= i;
}
// Here comes the division if needed
// After that, we swap the elements back
if (need_swap) {
// Note the double here
// If m is always > n then these lines are not needed
double fractional_result = (double)1 / result;
std::swap(m, n);
}
另外要提一下(如果你需要一些大的int实现并希望自己做) - 最好的方法就是将你的int视为一系列的块,最好是将你的int拆分到系列,每个包含4位数。
示例:1234 | 4567 | 2323 | 2345 | ...
。然后你将必须实现你需要的每一个基本操作(总和,多,也许是战争,分裂实际上是一个艰难的)。
答案 7 :(得分:0)
解决x!/ y!对于x> Y:
int product = 1;
for(int i=0; i < x - y; i ++)
{
product *= x-i;
}
如果y> x切换变量并采用解决方案的倒数。
答案 8 :(得分:0)
我问了一个类似的问题,并得到了一些图书馆的指示:
How can I calculate a factorial in C# using a library call?
这取决于您是否需要所有数字,或者只是关闭。如果你只是想要一些接近的东西,Stirling's Approximation是一个很好的起点。