Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 非常大数的二项式系数对数逼近_C++_C++11_Math_Approximation_Binomial Coefficients - Fatal编程技术网

C++ 非常大数的二项式系数对数逼近

C++ 非常大数的二项式系数对数逼近,c++,c++11,math,approximation,binomial-coefficients,C++,C++11,Math,Approximation,Binomial Coefficients,我目前正在努力计算非常大的数的二项式系数,比如说n选择k,n

我目前正在努力计算非常大的数的二项式系数,比如说n选择k,n<10000000,n 到目前为止,我已经尝试了许多方法来处理这些计算所产生的大量数据。然而,问题是我不需要计算这些二项式系数一次,而是数十万次。这意味着计算阶乘的常规方法过于昂贵,而像long-long-int这样的标准数据类型过于有限,无法容纳这些数字

我已经尝试过Boost库中的多精度数据类型,但正如我所提到的,多次计算会导致非常慢的性能。我也尝试过使用OpenMP实现多线程,但性能优势仍然太低。因此,我转而计算二项式系数的对数,以保持数值较小。虽然这解决了数量大的问题,但这并没有加快进程。这就是为什么我尝试了对数二项式系数的斯特林近似。我当前的解决方案如下所示:

#include <math.h>

long double calc_hgeom(unsigned int k, unsigned int n, unsigned int K, unsigned int N)
{
    long double hprob = std::exp((log_C(K, k) + log_C(N-K, n-k)) - log_C(N, n));
    return hprob;
}

long double log_C(unsigned int u, unsigned int m)
{
    long double C = u * std::log(u) - m * std::log(m) - (u-m) * std::log(u-m)) + 0.5 * (std::log(u) - std::log(m) - std::log(u-m) - std::log(2*M_PI));
    return C;
}
然而,结果与实际值相差很大,高达7%。因此我的问题是:是否有一种有效的方法来计算二项式系数的对数,或者我的近似值是否可以改进以提高精度


任何帮助都将不胜感激,因为此计算是我整个算法的基础。

考虑R的lchoose函数

> choose(10000, 5000) 
[1] Inf
> lchoose(10000, 5000)
[1] 6926.641
BaseR语言源代码库是解决此类问题的理想来源

这里的技巧是使用ln转换的输入来避免溢出

请注意,该代码在GNU许可证下。

您应该用于n,应用于二项式系数,可以得到:

对于二项式系数本身,对于对数,只要取等式右侧的对数;这些东西很快就会变得简单得多。你仍然有k!不过,对于大k,你需要再次使用近似公式。最终你会得到一些更可行的东西,也就是说,数值上更稳定


如果这还不够好,也就是说,如果你仍然有几乎相互抵消的条件,考虑应用一个以上的变量。

你是否尝试添加斯特灵公式中的前两个修正项,如第三个公式中所给出的?这与后面近似部分中的其他公式相比如何?@LutzL:谢谢你的快速回复。我肯定会测试你提到的其他修正项,并比较准确度。这很奇怪。查看Wiki文章中的相对错误图,7%应该在n=100时传递。因此,对于n=1e7,第一近似值应该更好。非常感谢您的回答。事实上,泰勒展开是改进方法的一个好主意!我明天会试试这个。