I had an interesting encounter with a colleague, Bob, last week. We were talking about timing some calculations and we realized that the written code was actually measuring something different. Here's a small cautionary tale along with a neat factoid about vectors and for loops in MATLAB.
Contents
The Story
The story Bob and I started off with is less interesting than where we ended up. After looking at some code, I mentioned to Bob that using square brackets when there was no real concatenation was sometimes expensive in MATLAB. You'll see this as a message from mlint. We pared the code in question down to this:
dbtype forsquare1 %% forsquare 2 for j = 1:ntimes 3 for k=[1:theEnd] 4 k; 5 end 6 end
and set out to compare it with this code:
dbtype forparen1 %% forparen 2 for j = 1:ntimes 3 for k=(1:theEnd) 4 k; 5 end 6 end
Notice that the only difference between these M-files is the way format of the expression, the first one using square brackets and the second using parentheses to group the expression. We'll now set out to time the two M-files.
Prep
clc, clear ntimes = 10; ntotal = 1e7; theEnd = ntotal/ntimes;
[], measure with tic-toc
tic, forsquare, toc
Elapsed time is 42.060557 seconds.
(), measure with tic-toc
tic, forparen, toc
Elapsed time is 0.173959 seconds.
[], measure with cputime
t = cputime; forsquare, cputime-t
ans = 41.2794
(), measure with cputime
t = cputime; forparen, cputime-t
ans =
0.1702
Explanation
I am timing these on my home laptop with MATLAB R2006a. I have 512 MB of RAM and 1.70 GHz processor. I am performing the timings with both tic toc and cputime tic - toc is easier, but I am not being too careful about what else is running on my machine so I am also using cputime. As you can see, it doesn't make much difference in this case. The construct with the [] is noticeably slower. Why is that?
In forsquare, the for loop expression delimited by the square brackets [] first constructs the full array inside the brackets in preparation for concatenating the array. In this case, there is nothing else being tacked on, so we create the full vector, ntotal elements in length. However, in the case of forparen, the parentheses () are used solely for grouping and MATLAB recognizes the expression as one it can expand during the execution of the for loop. In forsquare we create a large vector and that allocation dominates the time of the operation. In case you don't believe me that expressions in for loops are expanded as they are used, when possible, here's some code to look at:
dbtype forinf1 %% forinf 2 for j = 1:Inf 3 if j > 17 4 break 5 end 6 end
Notice that the end of the for expression is Inf ! There's no way I have enough memory to create this vector, and yet the code runs just fine:
tic, forinf, toc
Elapsed time is 0.000061 seconds.
Remarks
Timing is a delicate matter. Be sure you know what exactly you are timing when you make comparisons. Do you have any timing war stories to share?
Published with MATLAB® 7.2



Sorry for the truncation on the first release of this article.
–Loren
I had often wondered about the use of 1:Inf in a for loop. So now I know. Thanks. Which category does
for k=1:theEnd
fit? Is it square or paren?
- Steve
Steve-
Regular colon notation in for loops fits into the paren behavior.
–Loren
Well it’s not exactly a timing issue but I have something to tell about my experience with matlab performance. I brought two of my habits from FORTRAN programming to this amazing Matlab world.
the first is most of the times it improves the speed dramatically if you use * instead of / if the Denominator is a constant for example instead of a/2 most of the times it helps if you use a*.5 (it makes sense but most of the times we forget to use it)
And one myth is it is better to write your if statements like this ‘if 1==a’ instead of ‘if a==1′ however I still don’t know if it is just a myth or not
And probably everyone knows how to use && ;)
Sia-
I don’t know which version of MATLAB you are using or how you are doing your timing. I used R2006a and ran this script:
N = 1; M = magic(2000); K = zeros(size(M)); t = cputime; for num = 1:N, K = M*0.5; end cputime-t t = cputime; for num = 1:N, K = M/2.0; end cputime-tand I basically see no difference in scalar multiplication vs. division.
I similarly tried timing 1==a vs. a==1 and found no difference. I am using a Windows XP laptop.
Loren, It’s not what I meant. you should use / instead of the *. I use R14 (no service pack) on a 2.4 XP laptop 1Gig Ram, please replace your code with this
clc
clear all;
N = 1;
M = magic(2000);
K = zeros(size(M));
t = cputime;
for num = 1:N,
K = M*.272423;
end
cputime-t
t = cputime;
for num = 1:N,
K = M/3.67076;
end
cputime-t
on mine it shows 30% better performance for * , however it is really dependant on the case you are solving. sometimes I see 300% improvement.
for the a==1 case I wrote this
clc;
clear all;
t=cputime;
for i=1:20000000
for j=i:5
if 2==j
alpha=200;
end
end
end
cputime-t
clear all;
t=cputime;
for i=1:20000000
for j=i:5
if j==2
alpha=200;
end
end
end
cputime-t
the difference was just 2 sec in 15 sec, but at least showed that the 1==a case was faster
have a good week
Sia-
I fixed my typo in the comment above. I had compared /2 and *.5 in my timings and saw little difference. But I see some difference with your first set of numbers (but much smaller than the 30% you are seeing). Thanks for the interesting test cases.
There are obvious ways to vectorize some codes like these, but you can’t always do so.
–Loren
Constructs like if(1==a) above, where the literal is to the left of the “==” help prevent accidents like (if(a=1)). Faster in the sense that it’ll save bug fixing time :)
Interesting. The fact that Matlab does funky stuff in the for-loop explains why some stuff I tried to do once didn’t work.