6 Branching & Looping I
The programs that we have presented up to this point have been completely linear – a fixed sequence of steps with no ability to change behavior based on conditions. Further, they sometimes contained duplicate code; to perform the same operation multiple times on different values, we repeated the instructions or ran the program multiple times.
This chapter presents structures to give your program intelligence, i.e. the ability to take different actions depending on conditions, and to repeat operations on a set of values without duplicating the code.
6.1 Conditional Execution – the if
Statement
The simplest decision that a program can make is whether to execute a block of code or not, depending on conditions. For example, a banking program may deduct a payment from a customer’s account, but only if the account balance is at least as great as the payment amount. A MATLAB implementation of this operation is:
%Deduct payment from balance if account has sufficient funds
if payment_amount <= balance
balance = balance - payment_amount;
fprintf ('Your new balance is %.2f\n', balance);
end
For this code to execute properly, the variables payment_amount
and balance
must have been assigned values earlier in the program.
An if
statement has 3 required elements:
- The keyword
if
, followed by a conditional statement. The conditional typically contains one or more relational operators (>, <, ==, etc.). Often there will be equivalent ways of writing the same condition. In this example, the condition could just as well have been written asbalance >= payment_amount
- A block of code to be executed if and only if the condition is true. While the example above is almost trivially short, this block can be arbitrarily complex – it can even contain other if statements or loops, as will be discussed later in this chapter.
- The keyword
end
. This indicates to MATLAB where the block of code that is conditionally executed ends. Any code that comes after theend
statement is executed whether the condition is true or not.
Notice that the lines of code between the if
and end
have been indented. This is a standard practice to improve readability, but it is not required in MATLAB. (There are some languages, such as Python, which require indenting.)
Checkpoint 6.1 – 6.2: if Statement
6.2 Branching – the if...else
Structure
The if
statement described in the previous section executes or does not execute a single block of code, depending on a condition. Often, a program must choose which of two blocks of code to execute, depending on a condition. To make the banking program from the previous section more complete, a second block of code could be added to apply an overdraft penalty and display a suitable message if the account balance is less than the payment amount. One MATLAB implementation is:
%Assume that variables payment_amount, balance, and penalty have been defined previously
%Deduct payment from balance if account has sufficient funds
if payment_amount <= balance
balance = balance - payment_amount;
fprintf ('Your new balance is %.2f\n', balance);
else %this block will be executed if the condition is false
balance = balance - penalty;
fprintf ('Insufficient funds. An overdaft penalty of %.2f has been applied.\n', balance);
fprintf ('Your new balance is %.2f\n', balance);
end
In an if...else
structure, one or the other of two blocks of code is executed. If the condition is true, the first block is executed; otherwise the second one is.
Some important syntax notes:
- There is only a single
end
statement after the else block. Do NOT put anend
before theelse
statement. - There should be no condition after
else
. The else block will be executed if and only if the condition in theif
statement is false. Any condition that appears with theelse
is extraneous.
Checkpoint 6.3: if…else
6.3 Multiple Branches – the if...elseif...else
Structure
In some cases a program must switch among 3 or more blocks of code (branches). One way to do this in MATLAB is with the if...elseif...else
structure. The banking program can be expanded further so that it only deducts the overdraft penalty if the account has enough funds to cover the penalty, so that the balance does not become negative. (In reality, most banks are not this considerate – they will allow your balance to go negative!)
%Deduct payment from balance if account has sufficient funds
if payment_amount <= balance
balance = balance - payment_amount;
fprintf ('Your new balance is %.2f\n', balance);
elseif penalty <= balance
%if the balance cannot cover the payment, but it CAN cover the penalty
balance = balance - penalty;
fprintf ('Insufficient funds. An overdaft penalty of %.2f has been applied.\n', penalty);
fprintf ('Your new balance is %.2f\n', balance);
else %this will execute if neither of the two conditions are true
balance = 0;
fprintf('Insufficient funds to cover the payment or the overdraft penalty.\n')
fprintf('Your new balance is 0.\n');
end
Some important points about the if...elseif...else
structure:
- Exactly one of the blocks of code will be executed. If the
if
condition is true, the first block of code is executed, and the remaining blocks are skipped, even if theelseif
condition is also true. - There can be multiple
elseif
clauses, each of which will have a conditional statement. If more than one of the conditions are true, the first one that is true is the one that matters. That is, when a true condition is encountered, the corresponding block of code is executed, and the subsequent blocks (up to theend
statement) are skipped.
The following example illustrates the use of multiple elseif clauses to apply multiple conditions. The user is prompted to enter his height in inches and weight in pounds; the user’s body mass index is calculated, and depending on the range in which it falls, a weight classification is displayed.
When this example was run, the user entered values of 70 for height and 200 for weight, resulting in a BMI value of 28.7. Since the first condition (BMI > 30
) is false, the second condition (BMI > 25) is checked; it is true, so the message ‘Your weight classification is overweight’ is displayed, and the remaining blocks are skipped.
A common misconception is that the elseif
clauses should have compound conditions, e.g. elseif BMI > 25 && BMI <= 30
. The second condition is not necessary, since the elseif
clause is not evaluated unless it has already been determined that BMI <= 30.
Lecture Video 6.1 – if Statements
6.4 Multiple Branches – the switch
statement
There is an alternative to the if...elseif...else
structure called the switch
statement. The switch
is used when the variable that is the basis for branching takes a finite number of discrete values. As a rule of thumb, if all of the conditional statements in an if...elseif...else
structure use the == operator, it can be replaced by a switch
.
Here is an example of the same functionality implemented two ways – with an if...elseif...else
and with a switch
. The variables a, b, and c contain the coefficients of a quadratic, and the program calculates the real roots. If the discriminant (b2 – 4ac) is less than 0, there are no real roots; if it is equal to 0, there is a double root; if it is greater than 0 there are two, distinct real roots. The if...elseif...else
implementation is as follows:
%Calculating the real roots of a quadratic
%The values of a, b, and c have been assigned previously
discriminant = b^2 - 4*a*c;
if discriminant < 0
fprintf ('There are no real roots.');
elseif discriminant == 0
root = -b / (2*a);
fprintf ('There is a double root with the value %.2f\n', root);
else
root1 = (-b + sqrt(discriminant)) / (2*a);
root2 = (-b - sqrt(discriminant)) / (2*a);
fprintf ('There are two roots with the values %.2f and %.2f\n', root1, root2);
end
To use a switch
statement, there must be a variable that takes discrete values. That can be accomplished in this case with the sign(
) function, which returns -1, 0, or +1, depending on the sign of its argument. The equivalent program is as follows:
%Calculating the real roots of a quadratic
%The values of a, b, and c have been assigned previously
discriminant = b^2 - 4*a*c;
sign_of_D = sign(discriminant); %this will be -1, 0, or 1, for discriminant negative, zero, or positive
switch sign_of_D
case -1
fprintf ('There are no real roots.');
case 0
root = -b / (2*a);
fprintf ('There is a double root with the value %.2f\n', root);
case 1
root1 = (-b + sqrt(discriminant)) / (2*a);
root2 = (-b - sqrt(discriminant)) / (2*a);
fprintf ('There are two roots with the values %.2f and %.2f\n', root1, root2);
otherwise %this shouldn't happen; allows for errors such as a, b, or c not being defined correctly
fprintf('Something went wrong in the calculations\n');
end
The required elements of a switch
statement are:
- The keyword
switch
followed by a variable name or expression - One or more
case
statements, each with a value or list of values in { } - OPTIONAL: the keyword
otherwise
, which functions similarly toelse.
The block of code followingotherwise
will be executed if the switch variable does not match any of the cases - The keyword
end
The most common mistake with the switch
structure is to include a conditional expression in the case
statement, for example:
%Don't include a conditional in the %case statement like this:
switch x
case x == 1 %WRONG!
Some other key points:
- since the switch variable has to take discrete values, it is usually an integer, character or string. It should never be a floating-point number.
- If there is more than one value of the variable that corresponds to a given case, the values are listed in { }, e.g.
case {0, 1, 2}.
(This cannot be written as a range, like {0 : 2})
The following example, a program to convert pressure units, shows a switch
based on the value of a character array variable. It allows for some variation in the spelling and capitalization of units.
Lecture Video 6.2 – switch Statement
Checkpoint 6.4: if…elseif…else
6.5 Repetition – the for
Loop
Computer programs typically involve much repetition. If a calculation only has to be done once, writing a program to do it might take longer than doing the calculation on a hand-held calculator. Performing the calculation hundreds or thousands of times is a different matter. A basic structure of programming that avoids unnecessary duplication of code or running a program multiple times is a loop. In MATLAB, as in many languages, there are two types of loops: the for
or counted loop, and the while
or conditional loop. At a fundamental level, the two types of loop are really equivalent – anything that can be done with a for
can be done with a while
and vice versa. In most circumstances one or the other will be a more natural solution to a given problem.
The for
loop is typically used when the number of repetitions (or “iterations” in technical terminology) is known in advance, either because the operation has to be performed a fixed number of times, or because it is going to be applied to a fixed data array. If the number of iterations is not known in advance, because it depends on some condition being reached, a while
loop is more appropriate.
The presentation below illustrates the operation of a for
loop in the simplest application – repeating an operation a fixed number of times. It is important to understand that fundamentally, a for
loop in MATLAB iterates over an array. That is, it repeats the block of code (everything between the for
and end
statements) for each element of a provided array.
Presentation 6.1: Operation of a for Loop
The syntax of the for
loop requires the following elements:
- the keyword
for
- (on the same line as
for
) an assignment statement of the form variable_name = array. - a block of code to be executed on each iteration of the loop
- the keyword
end
Important notes:
- In some applications of the for loop, the variable may serve no purpose other than to count the number of times that the loop has been executed, but it is required nonetheless.
- The array can be specified by any valid method, not just with the : operator, and it does not have to be a monotonic sequence. All of the following are valid:
for k = 1: 10
for j = 2: 2: 20
for name = ["Jim", "Joe", "Frank"]
for x = X %where X is an array that was previously defined
for angle = linspace(-pi, pi, 100) %where X is an array that was previously defined
As with the if statement, indentation of the code between the for
and end
statements is recommended for readability, but not required.
Lecture Videos 6.3-6.4 – for Loop
Checkpoint 6.5: for loop
6.6 Conditional Repetition – the while
Loop
A while
loop executes a block of code as long as some condition is true. It is typically used in cases where the number of times that the loop will be executed is not known (or cannot easily be calculated) in advance. Consider a more elaborate version of the banking program, which pays a list of bills in order of importance until the account runs out of money. The first version is rather incomplete – astute readers will notice that it has some flaws – but it is sufficient to introduce the basic structure.
%list of bills to pay in order of importance
%values must have been assigned to the individual variables (mortgage, car, etc.) previously
bills = [mortgage, car, electricity, water, gas, insurance, cable];
j = 1; % a counter to indicate which bill will be paid next - start with the first
while bills(j) <= balance %keep paying bills as long account balance is enough to cover the next bill
balance = balance - bills(j); %deduct that amount from the account balance
j = j + 1; %go to the next bill
end
The while loop has several essential elements:
- the keyword
while
followed by a conditional statement - initialization of variables used in the conditional; in this example, the array
bills
and the variablesj
andbalance
must have been initialized before the while loop, or an “undefined variable” error will occur - a block of code to be repeated. The code must take some action that could cause the condition to become false; otherwise the loop will never stop – what is known as an “infinite loop.” In this example, the balance is reduced on each iteration of the loop, so that eventually the balance may become less than the next bill. (But it may not, which is one of the flaws mentioned above.)
- the keyword
end
Checkpoint 6.6: while loop
The last implementation of the banking program has a fatal flaw – it assumes that the initial balance is not enough to pay all of the bills, so that the loop will stop when the remaining balance is less than the next bill to be paid. Think about what will happen if that assumption is wrong, and then we will discuss how to fix it.
Checkpoint 6.7: while loop
Lecture Video 6.5 – while Loop
Checkpoint 6.8: while loop with compound condition
6.7 Simple Interactive Programs; Combining Looping and Branching
A common use of the while loop is to control execution of the program based on input from the user. Consider an implementation of the “guess the number” game, in which the computer generates a random number between 1 and 100, and the user is asked to guess. On each iteration of the loop, the user is prompted for a new guess and given feedback about whether his guess is too high or too low. The loop terminates when the user guesses correctly. (A better version would impose a limit on the number of guesses, but we leave that as an exercise.)
This example illustrates how looping and branching can work together to build complex functionality. In the next chapter we will explore this in more detail, but for now let’s look at the banking program one last time and fix its remaining shortcoming.
It might have occurred to you that the program may not be paying as many bills as it can. The problem is that it stops if the next bill is greater than the remaining balance, without checking if there might be a lower-priority bill that could be paid. For example, suppose the values are:
balance = 2000;
mortgage = 1400;
car = 400;
electricity = 250;
water = 45;
gas = 75;
etc.
Our program will stop after paying the mortgage and car payments, since the remaining balance (200) would not be sufficient to pay the electricity bill. However the water and gas bills could be paid – the program gave up too soon.
There are several solutions to this problem; one is shown here, where the while
loop is replaced by a for
loop with an if
statement. This version of the program looks at every bill, but only pays each one if the remaining balance is sufficient.
%list of bills to pay in order of importance
%values must have been assigned to the individual variables (mortgage, car, etc.) previously
bills = [mortgage, car, electricity, water, gas, insurance, cable];
for j = 1:length(bills) %loop over all bills
%if the balance is sufficient to pay the next bill, pay it
%otherwise, just go to the next bill
if balance > bills (j)
balance = balance - bills(j); %deduct that amount from the account balance
end %this is the end of the if statement
end %This is the end of the for loop
Take note that in a for
loop initialization and incrementing of the loop counter ( j
in this example)
happens automatically – it is not necessary to do these steps explicitly, as with a while
loop.
Checkpoint 6.9: Looping with Branching
Iterative Calculations
A common application of the while
loop is iterative calculations – that is, performing successive refinements to a calculation until the desired precision is reached. A simple example is summing a power series. Terms are added to the sum until the contribution from the next term is small enough to be ignored. The following example gives a function to calculate the Taylor series for [latex]e^x[/latex]:
[latex]e^x = \sum_{n=0}^{\infty} \frac{x^n}{n!}[/latex]
This function uses a tolerance of 10-6; that is, terms smaller than this are regarded as negligible.
function y = e_to_the_x(x)
y = 0; %initial value of the sum is 0, since no terms have been added
n=0; %start with the 0th term
next_term = x^n/factorial(n); %calculate the first term
%continue adding terms until the next term is negligible
while abs(next_term) > 1e-6
y = y + next_term; %add the nth term to the sum
n = n+1; %increment the value of n (go to the next term)
next_term = x^n/factorial(n); %calculate the next term
end
end
For an example of applying an iterative method to a mechanics problem, watch this video. (Note: in previous semesters, the problem being discussed was assigned as an application assignment. You may or may not have been assigned this problem.)
Lecture Video 6.6: Iterative Calculation
(If the video does not load, try logging into mediasite.osu.edu in a separate tab, then reload the page. Or you can use this direct link.)
6.8 Equivalence of for
and while
loops; the break
Statement
For a given for loop it is fairly straightforward to write a while loop to perform the same function. Here are some examples of equivalent for and while loops.
%simple counted loop
for k = 1:10 do_something(k); end
|
k = 1:
while k <= 10 do_something(k); k = k + 1; end
|
%iterating over a data array without indexing
X = [3, 11, 23, 37, 53] for x = X disp (isprime(x)) end
|
X = [3, 11, 23, 37, 53]
j = 1; while j <= length(X) disp (isprime (X(j)) j = j + 1; end
|
%iterating over a data array with indexing
for k = 1:length(data_array) perform_some_operation(data_array(k)); end
|
k =1;
while k <= length(data_array) perform_some_operation(data_array(k)); k = k + 1; end
|
It should be apparent that a for
loop is typically simpler than the equivalent while
loop. When the number of iterations is known in advance, the for
loop is preferred.
It is not as obvious that any while
loop can be replaced by an equivalent for
loop, but it is true, although it may be necessary to use an additional instruction, break
. The break
statement aborts the execution of a loop, as shown in the next example, which revisits the bill paying program. It might have occurred to you that if the account balance reaches zero, there is no point in looking at the remaining bills. In fact, if the balance becomes less than the smallest remaining bill, continuing is pointless. This version aborts the loop using a break
statement if that condition occurs.
%list of bills to pay in order of importance
%values must have been assigned to the individual variables (mortgage, car, etc.) %previously
bills = [mortgage, car, electricity, water, gas, insurance, cable];
for j = 1:length(bills) %loop over all bills
%if the balance is sufficient to pay the next bill, pay it
%otherwise, just go to the next bill
if balance > bills (j)
balance = balance - bills(j); %deduct that amount from the account balance
elseif balance < min(bills(j:end))
%if remaining balance is too small to pay any of the remaining bills, quit
break;
end %this is the end of the if statement
end %This is the end of the for loop
Of course, the same functionality could be achieved with a while
loop as follows:
%list of bills to pay in order of importance
%values must have been assigned to the individual variables (mortgage, car, etc.) previously
bills = [mortgage, car, electricity, water, gas, insurance, cable];
j = 1;
%loop over all bills as long as balance is sufficient to pay
%at least one more bill
while j <= length(bills) && balance >= bills(j:end)
%if the balance is sufficient to pay the next bill, pay it
%otherwise, just go to the next bill
if balance > bills (j)
balance = balance - bills(j); %deduct that amount from the account balance
end %this is the end of the if statement
j = j + 1;
end %This is the end of the loop
Which of these two approaches to use is a matter of style. One school of thought is that the break
statement should be avoided whenever possible, since it tends to break up the flow of the program. On the other hand, a break
is often a convenient way to accommodate a special case without having to completely restructure the code.
Lecture Video 6.7 – Loops vs. Vectorized Code
6.9 Mathworks Resources
For more details about MATLAB capabilities for branching and looping, see these Mathworks web pages:
Find an error? Have a suggestion for improvement? Please submit this survey.