Back to tutorial index

# The 'for-loop' and vectorizaton

## Introduction

In this lab, you will learn how to control the flow of execution of commands using a for loop.

Back to the top

## The 'for' loop

Up until now, commands in a script have been executed in the order in which they appear in a script. We can control this order of execution using flow control statements. The for loop is a type of flow control statement that allows us to execute a set of commands multiple times. For example, in the following code fragment, the statement fprintf('Hello, World\n') gets executed 10 times, even though it only appears once in the code fragment.

for i = 1:10,
fprintf('Hello, World!  This is iteration %d\n',i);
end
Hello, World!  This is iteration 1
Hello, World!  This is iteration 2
Hello, World!  This is iteration 3
Hello, World!  This is iteration 4
Hello, World!  This is iteration 5
Hello, World!  This is iteration 6
Hello, World!  This is iteration 7
Hello, World!  This is iteration 8
Hello, World!  This is iteration 9
Hello, World!  This is iteration 10


Back to the top

## The anatomy of the 'for' loop

The for loop has three basic components : the enclosing keywords for and end which enclose the set of statements to be carried out multiple times by the loop (the statement fprintf('Hello, World\n'), in the above example), a loop index which is the variable that stores the current value of the loop counter (i in the above example), and an index array containing the range of values over which the loop index should vary (the array 1:10 in the above example). See below for the "Anatomy of a "for" loop" Anatomy of a for loop

The number of times the loop executes the statements enclosed by the for and end is determined by the length of the array describing the loop range. Consider each of the following examples :

% Example 1
for i = 0:5:10,
fprintf('Three brown bears; i = %2d\n',i);
end
Three brown bears; i =  0
Three brown bears; i =  5
Three brown bears; i = 10

% Example 2
for x = [3.1 5.6],
fprintf('A couple of ducks; x = %4.1f\n',x);
end
A couple of ducks; x =  3.1
A couple of ducks; x =  5.6

% Example 3
for j = 10:-2:0,
fprintf('Six Simple Simons sitting on a stump; j = %2d\n',j);
end
Six Simple Simons sitting on a stump; j = 10
Six Simple Simons sitting on a stump; j =  8
Six Simple Simons sitting on a stump; j =  6
Six Simple Simons sitting on a stump; j =  4
Six Simple Simons sitting on a stump; j =  2
Six Simple Simons sitting on a stump; j =  0

% Example 4
for j = 1:-1:10,
fprintf('I am being ignored (:-((\n');
end

In each case, the statement enclosed by for loop was executed once for each entry in the loop index array. In the last example, the loop index array is empty, and so the enclosed statement did not get executed at all.

Back to the top

## The 'for' loop - using the loop index variable

In most cases, the statements enclosed by the for loop will involve the value of the loop index variable. Each of the following loop examples illustrates how we can make use of the loop index variable.

clear all;
% Example 1 - Print out the value of the loop index
for i = 0:2:20,
fprintf('i = %d\n',i);
end
i = 0
i = 2
i = 4
i = 6
i = 8
i = 10
i = 12
i = 14
i = 16
i = 18
i = 20

% Example 2 - Print out the entries in an array 'x', in reverse order.
x = rand(1,10);
for k = 10:-1:1,
fprintf('x(%2d) = %8.4f\n',k, x(k));
end
x(10) =   0.5785
x( 9) =   0.4886
x( 8) =   0.7303
x( 7) =   0.9289
x( 6) =   0.0292
x( 5) =   0.8010
x( 4) =   0.2625
x( 3) =   0.0855
x( 2) =   0.5079
x( 1) =   0.4242


Example 3 - Fill in entries in an array 'y' and print each value

for j = 1:8,
y(j) = sin(pi*(j-1)/2);
fprintf('y(%d) = %16.8f\n',j,y(j));
end
y(1) =       0.00000000
y(2) =       1.00000000
y(3) =       0.00000000
y(4) =      -1.00000000
y(5) =      -0.00000000
y(6) =       1.00000000
y(7) =       0.00000000
y(8) =      -1.00000000

% Example 4 - Cumulative sums of the integers 1 through 10.
s = 0;
for k = 1:10,
s = s + k;
fprintf('Sum of the numbers 1 to %2d : %5d\n',k, s);
end
Sum of the numbers 1 to  1 :     1
Sum of the numbers 1 to  2 :     3
Sum of the numbers 1 to  3 :     6
Sum of the numbers 1 to  4 :    10
Sum of the numbers 1 to  5 :    15
Sum of the numbers 1 to  6 :    21
Sum of the numbers 1 to  7 :    28
Sum of the numbers 1 to  8 :    36
Sum of the numbers 1 to  9 :    45
Sum of the numbers 1 to 10 :    55


In all of the above examples, the loop index is an integer. This is by far the most common loop index array for the for loop. However, there is nothing in Matlab to prevent us from trying the following unusual (and not particularly recommended) ways to use the loop index.

% Example 5 - A confusing example in which 'x' is an array and 'y' takes on
% different values in the array 'x'.
x = linspace(-1,1,7);
for y = x,
fprintf('y = %f\n',y);
end
y = -1.000000
y = -0.666667
y = -0.333333
y = 0.000000
y = 0.333333
y = 0.666667
y = 1.000000

% Example 6 - Let's see what we can do with strings.
for c = ['Hello', 'Goodbye','See Ya!'],
fprintf('%s',c);
end
HelloGoodbyeSee Ya!

In the first case, the loop index array x is an array containing non-integer values, but the loop index y still takes on each value, and the print statement is executed the expected number of times, e.g. one time for each entry in x.

The second example is less familar, but only because we have not worked with strings much. Here, the loop in index is the array of characters

s = ['Hello', 'Goodbye','See Ya!']
s =

HelloGoodbyeSee Ya!



We can index into this array in exactly the same way as with numeric data. For example,

s(1:10)
ans =

HelloGoodb



We can also use the length function to get the length of s. This length tells us the number of times the statements in the for will be executed.

length(s)
ans =

19



So in this case as well, the for loop above is behaving exactly as expected. Notice that we did not put a new line character into the fprintf statement in the the loop. If we had, our output for the odd 'string' loop would look like the following. We have added a loop counter here as well to see that the in fact, the number of times that the code inside the loop is called is equal to the length of the loop index array. In this case, the variable k acts like the loop index variable and is incremented by 1 each time the code in the loop is executed.

% add a new line character to the fprintf statement.
k = 1;
for c = ['Hello', 'Goodbye','See Ya!'],
fprintf('%2d   %s\n',k,c);
k = k + 1;
end
 1   H
2   e
3   l
4   l
5   o
6   G
7   o
8   o
9   d
10   b
11   y
12   e
13   S
14   e
15   e
16
17   Y
18   a
19   !


A final, entertaining example involves the use of a "cell" array. We will not discuss cell arrays in detail now, but suppose you really wanted to loop over a list of words. The following syntax will allow you to do this:

for word = {'Howdy', 'Later', 'Cheerio'},
fprintf('%s\n',word{:});
end
fprintf('The last word is ''%s''\n',word{:});
Howdy
Later
Cheerio
The last word is 'Cheerio'


As this example illustrates, the value of the loop index after we have completed the loop is the last value in the loop index array.

Back to the top

## Rules for using the 'for' loop

Here are some basic principles to follow when using the for loop.

Rules and guidelines for the for loop.
1. The for loop may enclose multiple Matlab statements,
2. The number of times that enclosed statements get executed is equal to the length of the loop index array,
3. The loop index variable may be used by the enclosed statements,
4. One for loop may be nested inside of one another loop. Statements in the inner for loops may use the loop index variable from the outer loop.
5. Loop index arrays most commonly contain integer values. Loop indices are often named i, j, k, m or n. Avoid the use of variable names x, y, z or w for loop indices.

Back to the top

## When to vectorize?

Often in Matlab, loops can be avoided by vectorizing the statements inside. In the following examples, a for loop can easily be replaced with a single of vectorized code. Notice that the print statements have also been vectorized.

Example

% for-loop : y = 10*x + 1
x = rand(1,5);
y = zeros(size(x));  % Avoid warnings!
for i = 1:5,
y(i) = 10*x(i) + 1;
fprintf('x(%d) = %8.4f; y(%d) = %8.4f\n',i,x(i),i,y(i));
end
x(1) =   0.2373; y(1) =   3.3728
x(2) =   0.4588; y(2) =   5.5885
x(3) =   0.9631; y(3) =  10.6309
x(4) =   0.5468; y(4) =   6.4681
x(5) =   0.5211; y(5) =   6.2114

% Vectorized equivalent (preferable!)
y = 10*x + 1;

% Vectorized print statement
fprintf('x(%d) = %8.4f; y(%d) = %8.4f\n',[1:5; x; 1:5; y]);
x(1) =   0.2373; y(1) =   3.3728
x(2) =   0.4588; y(2) =   5.5885
x(3) =   0.9631; y(3) =  10.6309
x(4) =   0.5468; y(4) =   6.4681
x(5) =   0.5211; y(5) =   6.2114


Example

% for-loop : y = sin(pi*x/4) over  [0,2*pi]
for j = 1:9,
y(j) = sin(pi*(j-1)/4);
fprintf('y(%d) = %16.8f\n',j,y(j));
end
y(1) =       0.00000000
y(2) =       0.70710678
y(3) =       1.00000000
y(4) =       0.70710678
y(5) =       0.00000000
y(6) =      -0.70710678
y(7) =      -1.00000000
y(8) =      -0.70710678
y(9) =      -0.00000000

% vectorized equivalent (preferable!)
y = sin(pi*((0:8)/4));    % Parenthesis around  (0:8) are important here!

% Vectorized print statement
fprintf('y(%d) = %16.8f\n',[1:9; y]);
y(1) =       0.00000000
y(2) =       0.70710678
y(3) =       1.00000000
y(4) =       0.70710678
y(5) =       0.00000000
y(6) =      -0.70710678
y(7) =      -1.00000000
y(8) =      -0.70710678
y(9) =      -0.00000000


Example

% for-loop : Cumulative summation
s = 0;
y = zeros(1,10);
for k = 1:10,
s = s + k;
y(k) = s;
fprintf('Sum of the numbers 1 to %2d : %5d\n',k, y(k));
end
Sum of the numbers 1 to  1 :     1
Sum of the numbers 1 to  2 :     3
Sum of the numbers 1 to  3 :     6
Sum of the numbers 1 to  4 :    10
Sum of the numbers 1 to  5 :    15
Sum of the numbers 1 to  6 :    21
Sum of the numbers 1 to  7 :    28
Sum of the numbers 1 to  8 :    36
Sum of the numbers 1 to  9 :    45
Sum of the numbers 1 to 10 :    55

% vectorized equivalent
y = cumsum(1:10);

% Vectorized print statement
fprintf('Sum of the numbers 1 to %2d : %5d\n',[1:10; y]);
Sum of the numbers 1 to  1 :     1
Sum of the numbers 1 to  2 :     3
Sum of the numbers 1 to  3 :     6
Sum of the numbers 1 to  4 :    10
Sum of the numbers 1 to  5 :    15
Sum of the numbers 1 to  6 :    21
Sum of the numbers 1 to  7 :    28
Sum of the numbers 1 to  8 :    36
Sum of the numbers 1 to  9 :    45
Sum of the numbers 1 to 10 :    55


Example

Sometimes, vectorization will be many times faster than an equivalent loop. For example,

N = 1e7;
th = linspace(0,2*pi,N);
tic
for i = 1:N,
y(i) = sin(th(i));
end
t1 = toc;
% Vectorized statement
tic
y = sin(th);
t2 = toc;

fprintf('Time in loop                  : %8.4f\n',t1);
fprintf('Time in vectorized statement  : %8.4f\n',t2);
fprintf('The vectorized statement is %6.2f times faster\n',t1/t2);
Time in loop                  :   9.8038
Time in vectorized statement  :   0.0539
The vectorized statement is 181.87 times faster


There are many more examples of the above in which a vectorized statement is far preferable to using a loop.

Back to the top

While many common mathematical statements can be easily vectorized (and should be!) some complex programming tasks are not so obviously vectorizable. Below is an example of a programming task that is sufficiently complex, that one is tempted to leave it in a loop. Inside the loop, we are still using array vectorization, but there does not seem to be an easy way to vectorize the outer loop. As we will see, however, an advanced use of vectorization allows the computation to be done without any loops, which ultimately leads to a faster version of the code.

% -------------------------------------------------------------------
% Compute the minimum and maximum distance between all possible pairs of
% points in a set of points (x(i),y(i), i = 1,...n.
% -------------------------------------------------------------------
n = 15;
x = rand(1,n);    % x-coordinates, chosen at random from [0,1]
y = rand(1,n);    % y-coordinates, chosen at random from [0,1]

tic;
dmax = 0;
dmin = 100;
for i = 1:n,
% Compute the distance between the point (x(i),y(i)) and the
% array of points (x,y).  first, remove x(i),y(i) from
% list (so the minimum isn't just 0!).
x1 = x;
y1 = y;
x1(i) = [];   % Remove x(i) from list
y1(i) = [];   % Remove y(i) from list

% This is a vectorized statement.
d = sqrt((x(i) - x1).^2 + (y(i) - y1).^2);

% Find the maximum value in the array [d dmax]
dmax = max([d dmax]);

% Find the minimum value in the array [d dmax]
dmin = min([d dmin]);
end
t_loop = toc;
fprintf('Elapsed time for loop version %8.4e\n',t_loop);

for i = 1:n
% Plot the line connecting the points (x(i),y(i)) each  point in the
% array (x,y).
% This loop is "nested" inside of our outer loop.  While we could
% vectorize this loop, it might not be so easy to read, and probably
% doesn't save us much time.
for j = 1:n,
plot([x(i) x(j)],[y(i),y(j)],'b-','linewidth',2);
hold on;
end
end
fprintf('The minimum distance is %8.4f\n',dmin);
fprintf('The maximum distance is %8.4f\n',dmax);

% Plot a symbol at each point and add a title and axes labels.
plot(x,y,'r.','markersize',30,'linewidth',2);
set(gca,'fontsize',16,'fontweight','bold')
title('Point cloud');
xlabel('x-coordinate','fontsize',16);
ylabel('y-coordinate','fontsize',16);
axis([0 1 0 1]);

% Fix aspect ratio so the plot is square.
axis square;
Elapsed time for loop version 1.1545e-03
The minimum distance is   0.0475
The maximum distance is   1.0624 We can vectorize the part of the code that computes the minimum distance. with the following code

fprintf('Vectorized version\n');
tic;
e = ones(n,1);

% Main part of the code
dist = sqrt((e*x-(e*x).').^2 + (e*y-(e*y).').^2);
dist = dist + diag(nan*e);
dmax = max(dist(:));
dmin = min(dist(:));
t_vec = toc;
fprintf('Elapsed time in vectorized version : %8.4e\n',t_vec);
fprintf(['Vectorized version is about %4.0f%% faster \n',...
'than the non-vectorized version\n'],100*(t_loop-t_vec)/t_loop);
fprintf('The minimum distance is %8.4f\n',dmin);
fprintf('The maximum distance is %8.4f\n',dmax);
Vectorized version
Elapsed time in vectorized version : 4.5871e-03
Vectorized version is about -297% faster
than the non-vectorized version
The minimum distance is   0.0475
The maximum distance is   1.0624


Note : Timing results from Publish (used to produce this webpage) are not truly reflective of actual timing results, but relative timings for vectorized verses non-vectorized codes should be approximately correct.

Back to the top

## Lab exercises

Associate each of the Matlab functions min, max, sum, prod, cumsum, cumprod, mean, median, std with exactly one mathematical expression below. Then, compute the value of each mathematical expression by two different ways:
1. Using a single Matlab function
2. Using a for loop
Compare your results to make sure you get the same result for each case.

Put all of your commands into a script containing your solution to each problem. To start, first create an array $x$ of 100 random values using the rand function. For example,
x = rand(100,1);

You will use this array for each of the exercises.

Note: In most cases, it will be preferable to use the single Matlab command than the for loop!.
1. $\displaystyle{\sum_{k=1}^{n} x_k}$
2. $\displaystyle{\min_{1 \le k \le n} x_k}$
3. $\displaystyle{\frac{1}{n}\sum_{k=1}^n {x_k}}$
4. $\displaystyle{y_j = \prod_{k=1}^j {x_k}}$, for $j = 1,2,...,n$
5. $\displaystyle{\sqrt{\frac{1}{n-1}\sum_{k=1}^n (x_k - \mu)^2}}$, where $\displaystyle{\mu = \frac{1}{n}\sum_{k=1}^n x_k}$
6. $\displaystyle{n}$
7. Find the value $\sigma$ in $x$ such that half of the values $x_k$ are less than $\sigma$ and half are greater than $\sigma$.
8. $\displaystyle{\max_{1 \le k \le n} x_k}$
9. $\displaystyle{y_j = \sum_{k=1}^j {x_k}}$ for $j = 1,2,...,n$
10. $\displaystyle{\prod_{k=1}^{n} x_k}$

Using a for loop, demonstrate the convergence of the series expansions of the following functions. Evaluate each function at the indicated value.
1. $$\cos(x) = \sum_{n=0}^{\infty}\frac{(-1)^{n}x^{2n}}{(2n)!}$$ at $x=5.4$.
2. $$\exp(x) = \sum_{n=0}^{\infty} \frac{x^n}{n!}$$ at $x=0.2$.
3. $$\ln(1+x) = \sum_{n=0}^{\infty} \frac{(-1)^{n-1}x^n}{n}$$ at $x=-0.5$.

% Example : Problem 1 below can be computing using the 'sum' function
% and a 'for' loop.
n = 100;
x = rand(1,n);
s = 0;
for i = 1:n,
s = s + x(i);
end
fprintf('Result from ''sum'' function  : %24.16f\n',sum(x));
fprintf('Result from the ''for'' loop  : %24.16f\n',s);
Result from 'sum' function  :      48.9455387473140036
Result from the 'for' loop  :      48.9455387473140036 