优化两个嵌套的for循环和if-condition

时间:2016-08-11 17:07:45

标签: matlab for-loop optimization

我有以下代码,它贯穿两个嵌套的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 - 消费而且效率不高。

有没有办法优化这段代码,可能是使用适用于整个数组的矢量化函数?

2 个答案:

答案 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个数量级才能使这个代码在运行时间上产生显着的差异。