直觉
正如Daniel在他的answer中提到的,线性索引在RAM中占用更多的空间,而下标要小得多。
对于下标索引,在内部,Matlab不会创建线性索引,但它将使用(双)编译循环遍历所有元素。
另一方面,下标版本必须循环通过从外部传递的所有线性索引,这将需要更多的内存读取,因此将需要更长时间。
声明
>线性索引更快
>只要索引的总数相同
计时
从时间上我们看到了第一个索赔的直接确认,我们可以通过一些额外的测试来推断第二个索赔(下面)。
LOOPED
subs assignment: 0.2878s
linear assignment: 0.0812s
VECTORIZED
subs assignment: 0.0302s
linear assignment: 0.0862s
首先要求
我们可以用循环进行测试。子参数的数量是相同的,但线性索引直接指向感兴趣的元素,而下标在内部需要转换。
感兴趣的功能:
function B = subscriptedIndexing(A,row,col)
n = numel(row);
B = zeros(n);
for r = 1:n
for c = 1:n
B(r,c) = A(row(r),col(c));
end
end
end
function B = linearIndexing(A,index)
B = zeros(size(index));
for ii = 1:numel(index)
B(ii) = A(index(ii));
end
end
第二个要求
该声明是使用矢量化方法时观察到的速度差异的推论。
首先,向量化方法(与循环相反)加速了下标分配,而线性索引稍慢(可能没有统计学意义)。
其次,两种索引方法的唯一区别就是索引/下标的大小。我们想把这个作为唯一可能的时间差异的原因。另一个主要的玩家可以是JIT优化。
测试功能:
function B = subscriptedIndexingVect(A,row,col)
n = numel(row);
B = zeros(n);
B = A(row,col);
end
function B = linearIndexingVect(A,index)
B = zeros(size(index));
B = A(index);
end
注意:我保持B的多余的预分配,以保持矢量化和循环的方法相当。换句话说,时间差异只能来自索引和循环的内部实现。
所有测试都以:
function testFun(N)
A = magic(N);
row = 1:2:N;
col = 1:2:N;
[ind_x,ind_y] = ndgrid(row,col);
index = sub2ind(size(A),ind_x,ind_y);
% isequal(linearIndexing(A,index), subscriptedIndexing(A,row,col))
% isequal(linearIndexingVect(A,index), subscriptedIndexingVect(A,row,col))
fprintf('LOOPEDn')
fprintf(' subs assignment: %.4fsn', timeit(@()subscriptedIndexing(A,row,col)))
fprintf(' linear assignment: %.4fsnn',timeit(@()linearIndexing(A,index)))
fprintf('VECTORIZEDn')
fprintf(' subs assignment: %.4fsn', timeit(@()subscriptedIndexingVect(A,row,col)))
fprintf(' linear assignment: %.4fsn', timeit(@()linearIndexingVect(A,index)))
end
开启/关闭JIT没有影响:
feature accel off
testFun(5e3)
...
VECTORIZED
subs assignment: 0.0303s
linear assignment: 0.0873s
feature accel on
testFun(5e3)
...
VECTORIZED
subs assignment: 0.0303s
linear assignment: 0.0871s
这不包括下标分配的优越速度来自JIT优化,这使我们有唯一合理的原因,RAM访问次数。确定最终矩阵具有相同数量的元素。但是,线性赋值必须检索索引的所有元素才能获取数字。
建立
使用MATLAB R2015b测试Win7 64。由于Matlab’s execution engine最近的变化,Matlab的先前版本将提供不同的结果
事实上,在Matlab R2014a中关闭JIT会影响时序,但只对于循环(预期结果):
feature accel off
testFun(5e3)
LOOPED
subs assignment: 7.8915s
linear assignment: 6.4418s
VECTORIZED
subs assignment: 0.0295s
linear assignment: 0.0878s
这再一次证实,线性和Sibcripted赋值之间的时间差异应来自RAM访问次数,因为JIT在向量化方法中不起作用。