我有以下代码,它贯穿两个嵌套的for
- 循环,中间有一个if
条件:
N=1e4;
cond_array = [0:(N/2-1) -N/2+(0:(N/2-1))]/(N);
condition = 0.1;
arr_one = zeros(N, 1);
arr_two = zeros(N, 1);
for m=1:N
for k=1:N
if(abs(cond_array(k)) <= condition)
arr_one(m) = arr_one(m) + m*k;
else
arr_two(m) = arr_two(m) + m*k;
end
end
end
我想优化此代码,因为我可能需要使用非常大的N
(>1e4
),根据我自己的经验,for
- MATLAB中的循环通常非常CPU - 消费而且效率不高。
有没有办法优化这段代码,可能是使用适用于整个数组的矢量化函数?
答案 0 :(得分:4)
这是获得相同结果的更快(和可读)的方法:
N=1e4;
cond_array = [0:(N/2-1) -N/2+(0:(N/2-1))]/(N);
condition = 0.1;
% this is so you don't check the same condition multiple times:
cond = abs(cond_array)<=condition;
% a vector of the positions in 'arr_one' and 'arr_two':
pos = (1:N).';
% instead of m*k(1)+m*k(2)... use: m*sum(k):
k1 = sum(pos(cond)); % for arr_one
k2 = sum(pos(~cond));% for arr_two
% the final result:
arr_one = pos.*k1;
arr_two = pos.*k2;
对于您在评论中提到的第二种情况,m*k
变为exp((m-1)*(k-1))
,我们可以再次使用矢量化计算exp((m(1)-1)*(k(1)-1)) +...+ exp((m(1)-1)*(k(N)-1))...
的总和,然后使用一些最小循环来结束所有m
s:
% we define new vectors of constants:
k1 = pos(cond);
k2 = pos(~cond);
% define new functions for each of the arrays:
ek1 = @(m) sum(exp((m-1).*(k1-1)));
ek2 = @(m) sum(exp((m-1).*(k2-1)));
% and we use 'arrayfun' for the final result:
arr_one = arrayfun(ek1,1:N).';
arr_two = arrayfun(ek2,1:N).';
arrayfun
并不比for
循环快,只是更紧凑。使用for
循环将是这样的:
arr_one = zeros(N,1);
arr_two = zeros(N,1);
for k = 1:N
arr_one(k) = ek1(k);
arr_two(k) = ek2(k);
end
这是使用bsxfun
的另一个更通用的选项:
ek = @(m,k) exp((m-1).*(k-1));
arr_one = sum(bsxfun(ek,1:N,k1)).';
arr_two = sum(bsxfun(ek,1:N,k2)).';
答案 1 :(得分:0)
研究逻辑索引的使用。 如果不太了解你的代码,我想你可以通过类似于下面的数组函数来删除循环。
arr_one(abs(cond_array)<condition)
这将消除对比较功能的需要,这将允许您使用匿名array function来创建计算。
但是,如果我正确理解您的代码,您只需将条件索引的位置和数组索引的位置的乘积添加到数组中。 如果你这样做,那么做一些类似下面的事情要容易得多。
position=(1:N)'
arr_one(abs(cond_array)<condition)=arr_one(abs(cond_array)<condition)+position(abs(cond_array)<condition)
在此声明中,您要查找cond_array小于条件的所有项目,并添加位置(实际上是前一个示例中m和k的代理)。
就运行时而言,我认为你必须比1e4大1到3个数量级才能使这个代码在运行时间上产生显着的差异。