用于计算大因子的商的C ++程序

时间:2010-04-28 16:47:09

标签: c++

如何编写c ++程序来计算大因子。

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

9 个答案:

答案 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

在Linux上编译

答案 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是一个很好的起点。