我想计算多项系数:
令人满意n=n0+n1+n2
可以在函数中轻松完成此运算符的Matlab实现:
function N = nchooseks(k1,k2,k3)
N = factorial(k1+k2+k3)/(factorial(k1)*factorial(k2)*factorial(k3));
end
但是,当索引大于170时,因子将是无穷大,在某些情况下会产生NaN
,例如180!/(175! 3! 2!) -> Inf/Inf-> NaN
。
第一个解决方案似乎非常慢,所以我尝试了第二个选项:
function N = nchooseks(k1,k2,k3)
N = 10^(log_gamma(k1+k2+k3)-(log_gamma(k1)+log_gamma(k2)+log_gamma(k3)));
end
function y = log_gamma(x), y = log10(gamma(x+1)); end
我将原始和log_gamma实现与以下代码进行比较:
% Calculate
N=100; err = zeros(N,N,N);
for n1=1:N,
for n2=1:N,
for n3=1:N,
N1 = factorial(n1+n2+n3)/(factorial(n1)*factorial(n2)*factorial(n3));
N2 = 10^(log10(gamma(n1+n2+n3+1))-(log10(gamma(n1+1))+log10(gamma(n2+1))+log10(gamma(n3+1))));
err(n1,n2,n3) = abs(N1-N2);
end
end
end
% Plot histogram of errors
err_ = err(~isnan(err));
[nelements,centers] = hist(err_(:),1e2);
figure; bar(centers,nelements./numel(err_(:)));
但是,对于某些情况,结果略有不同,如下面的直方图所示。
因此,我应该假设我的实现是正确的还是数字错误不能证明数字偏差的合理性?
答案 0 :(得分:3)
为什么不用这个?它速度快,不会溢出:
N = prod([1:n]./[1:n0 1:n1 1:n2]);
答案 1 :(得分:2)
很抱歉复活旧帖子,但对于未来的搜索者,你几乎可以肯定只是将你的多项系数写成二项式系数的乘积,并使用内置方法计算二项式系数(或使用Pascal编写自己的系数)三角形或其他方法)。相关公式显示在Wikipedia section on multinomial coefficients的第一段中。 (我在这里写,但似乎没有办法渲染LaTeX。)
这种方法的另一个好处是它可以获得溢出,因为因子都是整数。计算多项式系数时,没有必要划分。
答案 2 :(得分:0)
使用@jemidiah提供的技巧
这是代码
function c = multicoeff (k),
c = 1;
for i=1:length(k),
c = c* bincoeff(sum(k(1:i)),k(i));
end;
end
和一些用法示例:
octave:88> multicoeff([2 2 2])
ans = 90
octave:89> factorial(6)/(factorial(2)*factorial(2)*factorial(2))
ans = 90
octave:90> multicoeff([5 4 3])
ans = 27720
octave:91> factorial(12)/(factorial(5)*factorial(4)*factorial(3))
ans = 27720
答案 3 :(得分:0)
另一种方法是使用Yannis Manolopoulos迭代方法。
假设我们有一个包含多项式项的向量k
。
function N = multicoeff (k),
n=sum(k);
[_,imax]=max(k);
num=[n:-1:n-k(imax)-1];
den=[]; k(imax)=[];
for i=1:length(k), den=[den 1:k(i)]; endfor;
N=prod(num./den);
endfunction
示例
octave:2> k = [5 4 3];
octave:3> multicoeff (k)
ans = 27720
参考: Yannis Manolopoulos。二项式系数计算。 ACM SIGCSE公告,34(4):65,2002年12月。doi:10.1145 / 820127.820168。 URL https: //doi.org/10.1145/820127.820168。