C++;计算大阶乘商的程序 如何编写一个C++程序来计算大阶乘?< /P>

C++;计算大阶乘商的程序 如何编写一个C++程序来计算大阶乘?< /P>,c++,C++,例如,如果我想计算(100!)/(99!),我们知道答案是100,但如果我单独计算分子和分母的阶乘,这两个数字都是巨大的。下面是一个如何计算的示例: 他们采用的方法是将大的存储为数字字符数组 还可以看到这样一个问题:您可以使用Gamma函数,看看哪些函数也指向代码。您可以使用一个大整数库,比如它可以处理任意大的整数。来解x/Y对于x>y: int product = 1; for(int i=0; i < x - y; i ++) { product *= x-i; } int

例如,如果我想计算(100!)/(99!),我们知道答案是100,但如果我单独计算分子和分母的阶乘,这两个数字都是巨大的。

下面是一个如何计算的示例:

他们采用的方法是将大的存储为数字字符数组


还可以看到这样一个问题:

您可以使用Gamma函数,看看哪些函数也指向代码。

您可以使用一个大整数库,比如它可以处理任意大的整数。

来解x/Y对于x>y:

int product = 1;
for(int i=0; i < x - y; i ++)
{
    product *= x-i;
}
int-product=1;
对于(int i=0;i

如果y>x切换变量并取你的解的倒数。

这里唯一可以进行的优化(考虑到in
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);
   }
if(m==n)返回1;
//如果“m”小于“n”,我们将
//先计算分母,然后
//一分为二
布尔需要交换=(mn;--i){
结果*=i;
}
//如果需要的话,分部来了
//在那之后,我们交换元素回来
如果(需要交换){
//注意这里的双精度
//如果m始终大于n,则不需要这些线
双分数结果=(双)1/结果;
标准:交换(m,n);
}
另外要提到的是(如果你需要一些大的int实现,并且想自己实现的话)——最好的方法不是很难实现,就是把int看作一个块序列,最好是把int分成一个序列,每个序列包含4位数字


示例:
1234 | 4567 | 2323 | 2345 |……
。然后你必须实现你需要的每一个基本操作(sum、mult、也许pow,除法实际上是一个困难的操作)。

我问了一个类似的问题,并得到了一些指向一些库的指针:


这取决于你是需要所有的数字,还是只需要接近的数字。如果你只想靠近某个地方,是一个好的开始。

< P>当然,这个特定的表达式应该被优化,但是对于标题问题,我喜欢它提供了一个不错的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;
}
#包括
#包括
mpz_类事实(无符号整数n)
{
mpz_课程成绩(n);
而(n-->1)结果*=n;
返回结果;
}
int main()
{
mpz_类结果=事实(100)/事实(99);

std::cout根据您的评论,您还需要计算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
i=96
j=4
结果=i
而(一)
如果(j>1)和(结果%j==0)
结果/=j
--j
其他的
结果*=i
++我
同样的道理,你当然可以比这更聪明


不过,这只是推迟了不可避免的事情:最终你达到了固定大小类型的极限。因数爆炸的速度如此之快,以至于在重载使用时,你将需要多重精度。

扩展德克的答案(我认为这是正确的答案):

#包括“math.h”
#包括“stdio.h”
int main(){
printf(“%lf\n”,(100.0/99.0)*exp(lgama(100)-lgama(99));
}

试试看,它真的能满足你的需要,尽管如果你不熟悉它,它看起来有点疯狂。使用bigint库会非常低效。获取gammas日志的EXP速度非常快。这会立即运行


需要乘以100/99的原因是gamma等于n-1!而不是n!。因此,可以只执行exp(lgama(101)-lgama(100))相反。此外,gamma的定义不仅仅是整数。

在我看来,你实际上是在试图避免计算大的阶乘。你可以在这里找到几个答案:你的问题是什么?你是在问如何用大的数字做算术,还是在问如何计算尽可能多的公式而不需要任何大的运算r大于
long
long-long
?可能的重复对排列和组合不起作用。例如,nPr和NCR在示例中效果良好,但在许多其他示例中失败。尝试100!/7!。问题是:“如何计算大阶乘?”顺便说一句,您应该在开始时将乘积设为1。 #include "math.h" #include "stdio.h" int main(){ printf("%lf\n", (100.0/99.0) * exp(lgamma(100)-lgamma(99)) ); }