我得到了一个赋值,我应该编写一个算法,通过重心公式执行多项式插值。公式表明:
p(x)=(SIGMA_(j = 0到n)w(j)* f(j)/(x-x(j)))/(SIGMA_(j = 0到n)w(j) /(x - x(j)))
我写了一个算法很好,我得到了我想要的多项式输出。但是,这需要使用一些相当长的循环,对于大的网格数,必须进行大量的非常循环操作。因此,如果有人对我如何改进这一点有任何暗示,我将非常感激,以便我将避免所有这些循环。
在算法中,x
和f
代表我们应该插入的给定点。 w
代表重心权重,它是在运行算法之前计算出来的。并且grid
是应该进行插值的空间:
function p = barycentric_formula(x,f,w,grid)
%Assert x-vectors and f-vectors have same length.
if length(x) ~= length(f)
sprintf('Not equal amounts of x- and y-values. Function is terminated.')
return;
end
n = length(x);
m = length(grid);
p = zeros(1,m);
% Loops for finding polynomial values at grid points. All values are
% calculated by the barycentric formula.
for i = 1:m
var = 0;
sum1 = 0;
sum2 = 0;
for j = 1:n
if grid(i) == x(j)
p(i) = f(j);
var = 1;
else
sum1 = sum1 + (w(j)*f(j))/(grid(i) - x(j));
sum2 = sum2 + (w(j)/(grid(i) - x(j)));
end
end
if var == 0
p(i) = sum1/sum2;
end
end
答案 0 :(得分:4)
这是matlab'矢量化'的经典案例。我会说 - 只需删除循环。这几乎就是这么简单。首先,看看这段代码:
function p = bf2(x, f, w, grid)
m = length(grid);
p = zeros(1,m);
for i = 1:m
var = grid(i)==x;
if any(var)
p(i) = f(var);
else
sum1 = sum((w.*f)./(grid(i) - x));
sum2 = sum(w./(grid(i) - x));
p(i) = sum1/sum2;
end
end
end
我删除了j
上的内循环。我在这里所做的就是删除(j)
索引并将算术运算符从/
更改为./
以及从*
更改为.*
- 同样,但是前面有一个点表示操作是逐个元素执行的。与普通矩阵运算符相比,这称为array operators。另请注意,处理网格点落在x
上的特殊情况与原始实现中的情况非常相似,只使用向量var
,使x(var)==grid(i)
。
现在,您还可以删除最外层的循环。这有点棘手,有两种主要方法可以在MATLAB中实现。我会以更简单的方式做到这一点,效率较低,但阅读更清晰 - 使用repmat
:
function p = bf3(x, f, w, grid)
% Find grid points that coincide with x.
% The below compares all grid values with all x values
% and returns a matrix of 0/1. 1 is in the (row,col)
% for which grid(row)==x(col)
var = bsxfun(@eq, grid', x);
% find the logical indexes of those x entries
varx = sum(var, 1)~=0;
% and of those grid entries
varp = sum(var, 2)~=0;
% Outer-most loop removal - use repmat to
% replicate the vectors into matrices.
% Thus, instead of having a loop over j
% you have matrices of values that would be
% referenced in the loop
ww = repmat(w, numel(grid), 1);
ff = repmat(f, numel(grid), 1);
xx = repmat(x, numel(grid), 1);
gg = repmat(grid', 1, numel(x));
% perform the calculations element-wise on the matrices
sum1 = sum((ww.*ff)./(gg - xx),2);
sum2 = sum(ww./(gg - xx),2);
p = sum1./sum2;
% fix the case where grid==x and return
p(varp) = f(varx);
end
完全矢量化版本可以使用bsxfun
而不是repmat
来实现。这可能会更快一些,因为矩阵没有明确形成。但是,对于小型系统,速度差异可能不大。
此外,具有一个循环的第一个解决方案在性能方面也不是太糟糕。我建议你测试那些并看看,哪个更好。也许完全矢量化是不值得的?第一个代码看起来更具可读性。