计算组合时溢出 我试图计算C++中的组合C(40, 20),但是C++中的数据类型似乎无法正确处理这个计算,即使我已经使用了长Lo/数据类型。以下是我的代码: #include <iostream> long long fac(int x) { register long long i,f = 1; // Optimize with regFunction for(i = 1;i <= x;i++) f *= i; std::cout << f << std::endl; return f; } // C(n,r) = n!/r!(n-r)! long long C(long long n, long long r) { return fac(n) / (fac(r) * fac(n - r)); } int main(int argc, char const *argv[]) { std::cout << C(40, 20) << std::endl; return 0; } #包括 长fac(int x){ 寄存器长i,f=1;//使用regFunction优化 对于(i=1;i

计算组合时溢出 我试图计算C++中的组合C(40, 20),但是C++中的数据类型似乎无法正确处理这个计算,即使我已经使用了长Lo/数据类型。以下是我的代码: #include <iostream> long long fac(int x) { register long long i,f = 1; // Optimize with regFunction for(i = 1;i <= x;i++) f *= i; std::cout << f << std::endl; return f; } // C(n,r) = n!/r!(n-r)! long long C(long long n, long long r) { return fac(n) / (fac(r) * fac(n - r)); } int main(int argc, char const *argv[]) { std::cout << C(40, 20) << std::endl; return 0; } #包括 长fac(int x){ 寄存器长i,f=1;//使用regFunction优化 对于(i=1;i,c++,C++,而言,即使使用uint64又名ulonglong,最大值也是18446744073709551615,而40!是8159152832478973434561126956115894272000000,这稍微大一点 我建议你用它来做这类数学问题是阶乘很快就变大了。40!太大了,无法存储在long中。幸运的是,你实际上不需要在这里计算这个数字,因为你可以在C(n,r)的计算中减少分数在计算它之前。这将产生方程式(来自): 由于k!(代码中的r!)比n!小得多,所以效果更好。不过,在某些情况下,它也

而言,即使使用uint64又名ulonglong,最大值也是
18446744073709551615
,而40!是
8159152832478973434561126956115894272000000
,这稍微大一点


我建议你用它来做这类数学

问题是阶乘很快就变大了。40!太大了,无法存储在
long
中。幸运的是,你实际上不需要在这里计算这个数字,因为你可以在
C(n,r)的计算中减少分数
在计算它之前。这将产生方程式(来自):

由于k!(代码中的r!)比n!小得多,所以效果更好。不过,在某些情况下,它也会崩溃


或者,您也可以通过实现递归算法来使用递归定义。但是,除非您记住中间结果,否则这将是非常低效的(指数运行时间)。

一个懒惰的解决方法是使用支持多精度的库,例如

正确安装后(可从大多数Linux发行版上的存储库中获得),可以归结为:

  • 添加
    #包括
    到源文件
  • long-long
    替换为
    mpz\u类
  • 使用
    -lgmpxx-lgmp编译
资料来源:

#include <iostream>
#include <gmpxx.h>

mpz_class fac(mpz_class x) {
    int i;
    mpz_class f(1); // Optimize with regFunction
    for(i = 1;i <= x;i++)
        f *= i;
    std::cout << f << std::endl;
    return f;
}

// C(n,r) = n!/r!(n-r)!
mpz_class C(mpz_class n, mpz_class r) {
    return fac(n) / (fac(r) * fac(n - r));
}

int main(int argc, char const *argv[]) {
    std::cout << C(40, 20) << std::endl;
    return 0;
}

如果你想彻底了解,你可以做更多的事情,但这会给你答案。

在乘法后立即执行除法,立即计算C:

long long C(long long n, long long r) 
{
    long long f = 1; // Optimize with regFunction
    for(auto i = 0; i < r;i++)
        f = (f * (n - i)) / (i + 1);
    return f ; 
}
long-long C(long-long n,long-long r)
{
long f=1;//使用regFunction进行优化
用于(自动i=0;i

结果应该是精确的(无余数的除法,直到溢出),因为(i+1)中的任何整数因子都已经存在于(n-i)中。(应该不太难证明)

您的数字增长太多,这是此类计算中的常见问题,恐怕没有直接的解决方案。即使您可能会减少一点乘法次数,也可能会导致
long

您可能想查看这些内容:


我知道在这个问题上有不同的算法方法。我记得有一些解决方案使用字符串来存储整数表示和东西,但正如@Konrad提到的,这可能是一个糟糕的方法。

嗯……你是说
C(40,20)
?另一种方法是没有意义的。如何从20个样本中选择40个样本?1.找到一种使用较小值进行计算的方法,或2.找到一种精度较低的计算方法,并使用
double
,或3.使用bignum库。@CoryKramer,谢谢我修改了它。使用字符串存储数字只是一个糟糕的方法-man的bignum库。与使用更好的库相比,它没有任何优势。是的,这可能是真的,我不确定我刚才提到的那部分。但我会编辑它,使它更清晰。这就是我写的,只要
k<21
@Thomas true;我已经添加了一点澄清。
long long C(long long n, long long r) 
{
    long long f = 1; // Optimize with regFunction
    for(auto i = 0; i < r;i++)
        f = (f * (n - i)) / (i + 1);
    return f ; 
}