2011-04-08 123 views
2

当我在MatLab中执行这些等效操作时,第一个运行时间为24.158371秒(for循环)。第二次运行在0.004976秒(逻辑索引)。 MatLab可能会做些什么让这个运行速度更快?这仍然是O(n)时间,对吧?这为什么这么快?

t = linspace(-2*pi,2*pi,100000); 
fd = 1e3; 
tau = 1e-6; 


% Calculate arbitrary function using a loop 
tic 
for tind = 1:length(t) 
    tester(tind) = cos(2*pi*fd*t(tind))/(2*pi*fd.*t(tind)); 
end 
toc 

pause; disp('Press a key'); 
% Same calculation with logical indexing 
tic 
tester2 = cos(2*pi*fd.*t)./(2*pi*fd.*t); 
toc 
+1

您的第一个循环代表了与第二个循环相同的更高层次的方法;即脚本看起来并不是最优化的。 – ThomasRS 2011-04-08 01:02:25

+0

这证实了Matlab循环吸吮的事实,如果有任何使用矩阵的方法,应该避免像瘟疫一样。 – Reinderien 2011-04-08 01:10:25

+3

@Reinderien - 不,你错了。循环中的问题是,tind从未被预分配。所以发生的每一次都是通过循环,数组tind必须在内存中重新分配。 – 2011-04-08 11:10:58

回答

5

您的第一个循环中最大的成本实际上来自动态调整数组大小tester。每次通过循环时,Matlab必须将现有阵列复制到内存中的新位置,并留出额外元素的空间。所以,对于循环的每次迭代来说,这是一个O(n)操作。如果您预先分配数组,它将运行得更快,例如

tic 
tester = zeros(100000,1); 
for tind = 1:length(t) 
    tester(tind) = cos(2*pi*fd*t(tind))/(2*pi*fd.*t(tind)); 
end 
toc 

在我的系统,我得到11.3秒原始循环,0.0013秒的矢量版本0.010秒,以用于预分配为tester内存循环。值得一提的是,其他许多具有可调整大小的数组的语言会根据数组的当前大小分配额外的空间块,因此通过每次追加一个元素来构建数组的成本仅为O(n log n) ,所以这是Matlab的一个特殊缺陷。

5

MATLAB的R2011a版本使得这种事情更快(什么?你还没有得到该版本吗?下载!),请参阅release note。在我的机器上,第一个循环需要0.02秒,第二个循环需要0.004秒。所以,预先分配仍然是一个好主意,但如果你不能做到这一点,你就不会处在一个非常糟糕的地方。