计算组合时溢出 我试图计算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
而言,即使使用uint64又名ulonglong,最大值也是计算组合时溢出 我试图计算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!小得多,所以效果更好。不过,在某些情况下,它也
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 ;
}