在尝试对特定的Matlab代码进行矢量化时,我找不到直接的函数来生成二项式系数列表。我能找到的最好的是nchoosek
,但由于一些莫名其妙的原因,这个函数只接受整数(不是整数向量)。我目前的解决方案如下:
mybinom = @(n) arrayfun(@nchoosek, n*ones(1,n), 1:n)
这为给定的n
值生成一组二项式系数。但是,由于二项式系数总是对称的,我知道我的工作量是必要的两倍。我确信我可以创建一个利用对称性的解决方案,但我确信它会牺牲可读性。
有没有比这更优雅的解决方案,也许使用我不知道的Matlab功能?请注意,我对使用符号工具箱不感兴趣。
答案 0 :(得分:3)
如果您想最大限度地减少操作,可以遵循以下几点:
n = 6;
k = 1:n;
result = [1 cumprod((n-k+1)./k)]
>> result
result =
1 6 15 20 15 6 1
这要求每个系数的操作非常少,因为每个系数都是利用先前计算的系数获得的。
如果考虑对称性,可以将操作次数减少大约一半:
m1 = floor(n/2);
m2 = ceil(n/2);
k = 1:m2;
result = [1 cumprod((n-k+1)./k)];
result(n+1:-1:m1+2) = result(1:m2);
答案 1 :(得分:2)
Luis Mendo解决方案的修改版本怎么样 - 但以对数:
n = 1e4;
m1 = floor(n/2);
m2 = ceil(n/2);
k = 1:m2;
% Attempt to compute real value
out0 = [1 cumprod((n-k+1)./k)];
out0(n+1:-1:m1+2) = out0(1:m2);
% In logarithms
out1 = [0 cumsum((log(n-k+1)) - log(k))];
out1(n+1:-1:m1+2) = out1(1:m2);
plot(log(out0) - out1, 'o-')
使用对数的优点是你可以设置n = 1e4;
并仍然可以获得实际值的良好近似值(nchoosek(1e4, 5e3)
返回Inf
,这是不强>一个很好的近似值!)。
编辑跟随霍希勒的评论
您可以使用gammaln
功能获得相同的结果,但速度并不快。这两个近似值似乎完全不同:
n = 1e7;
m1 = floor(n/2);
m2 = ceil(n/2);
k = 1:m2;
% In logarithms
tic
out1 = [0 cumsum((log(n-k+1)) - log(k))];
out1(n+1:-1:m1+2) = out1(1:m2);
toc
% Elapsed time is 0.912649 seconds.
tic
k = 0:m2;
out2 = gammaln(n + 1) - gammaln(k + 1) - gammaln(n - k + 1);
out2(n+1:-1:m1+2) = out2(1:m2);
toc
% Elapsed time is 1.020188 seconds.
tmp = out2 - out1;
plot(tmp, '.')
prctile(tmp, [0 2.5 25 50 75 97.5 100])
% 1.0e-006 *
% -0.2217 -0.1462 -0.0373 0.0363 0.1225 0.2943 0.3846
添加三个gammaln
比添加n
对数更差吗?或者反之亦然?
答案 2 :(得分:0)
仅适用于Octave
您可以使用bincoeff功能。
示例:bincoeff(5, 0:5)
德尔>
编辑: 我能想到的唯一改进就是这样。也许你已经想过这个简单的解决方案并且不喜欢它。
# Calculate only the first half
mybinomhalf = @(n) arrayfun(@nchoosek, n*ones(1,n/2+1), 0:n/2)
# pad your array symmetrically
mybinom = @(n) padarray(mybinomhalf(n), [0 n/2], 'symmetric', 'post')
# I couldn't test it and this line may not work