7.5: Working with Conditions
- Page ID
Some of the loops in the previous chapter don’t work if the value of n isn’t set correctly before the loop runs. For example, this loop computes the sum of the first n elements of a geometric sequence:
A1 = 1; total = 0; for i=1:n a = A1 * 0.5^(i-1); total = total + a; end ans = total
It works for any positive value of n, but what if n is negative? In that case, you get:
total = 0
Why? Because the expression 1:-1 means “all the numbers from 1 to -1, counting up by 1.” It’s not immediately obvious what that should mean, but MATLAB’s interpretation is that there aren’t any numbers that fit that description, so the result is
>> 1:-1 ans = 1x0 empty double row vector
The result is an empty vector with one row and 0 columns. If you loop over an empty vector, the loop never runs at all, which is why in this example the value of total is zero for any negative value of n.
If you’re sure that you’ll never make a mistake, and that the preconditions of your functions will always be satisfied, then you don’t have to check. But for the rest of us, it’s dangerous to write a script, like this one, that quietly produces the wrong answer (or at least a meaningless answer) if the input value is negative. A better alternative is to use an if statement.
The if statement allows you to check for certain conditions and execute statements if the conditions are met. In the previous example, we could write:
if n<0 ans = NaN end
The syntax is similar to a for loop. The first line specifies the condition we’re interested in; in this case we’re asking if n is negative. If it is, MATLAB executes the body of the statement, which is the indented sequence of statements between the if and the end.
MATLAB doesn’t require you to indent the body of an if statement, but it makes your code more readable, so you should do it. Don’t make me tell you again.
In this example, the “right” thing to do if n is negative is to set ans = NaN, which is a standard way to indicate that the result is undefined (not a number).
If the condition is not satisfied, the statements in the body are not executed. Sometimes there are alternative statements to execute when the condition is false. In that case you can extend the if statement with an else clause.
The complete version of the previous example might look like this:
if n<0 ans = NaN else A1 = 1; total = 0; for i=1:n a = A1 * 0.5^(i-1); total = total + a; end ans = total end
Statements like if and for that contain other statements are called compound statements. All compound statements end with... end.
In this example, one of the statements in the else clause is a for loop. Putting one compound statement inside another is legal and common, and sometimes called nesting.
The operators that compare values, like are called relational operators because they test the relationship between two values. The result of a relational operator is one of the logical values: either 1, which represents “true,” or 0, which represents “false.”
Relational operators often appear in if statements, but you can also evaluate them at the prompt:
>> x = 5; >> x < 10 ans = 1
You can assign a logical value to a variable:
>> flag = x > 10 flag = 0
A variable that contains a logical value is often called a flag because it flags the status of some condition.
The other relational operators are =, which are self-explanatory, ==, for “equal,” and
~=, for “not equal.”
Don’t forget that == is the operator that tests equality, and = is the assignment operator. If you try to use = in an if statement, you get an error:
>> if x=5 if x=5 | Error: Incorrect use of '=' operator. To assign a value to a variable, use '='. To compare values for equality, use '=='. Did you mean: >> x = 5
In this case, the error message is pretty helpful.
To test if a number falls in an interval, you might be tempted to write something like 0 < x < 10, but that would be wrong, so very wrong. Unfortunately, in many cases, you’ll get the right answer for the wrong reason. For example:
>> x = 5; >> 0 < x < 10 % right for the wrong reason ans = 1
But don’t be fooled!
>> x = 17 >> 0 < x < 10 % just plain wrong ans = 1
The problem is that MATLAB is evaluating the operators from left to right, so first it checks if 0<x. It is, so the result is 1. Then it compares the logical value 1 (not the value of x) to 10. Since 1<10, the result is true, even though x is not in the interval.
For beginning programmers, this is an evil, evil bug!
One way around this problem is to use a nested if statement to check the two conditions separately:
ans = 0 if x>0 if x<10 ans = 1 end end
But it’s more concise to use the AND operator, &&, to combine the conditions.
>> x = 5; >> x>0 && x<10 ans = 1 >> x = 17; >> x>0 && x<10 ans = 0
The result of AND is true if both of the operands are true. The OR operator, ||, is true if either or both of the operands are true.
However, you have to be careful with the range of the loop. In the previous version, the loop runs from 3 to n, and each time we assign a value to the ith element.
It would also work to “shift” the index over by two, running the loop from 1 to n-2:
F(1) = 1 F(2) = 1 for i=1:n-2 F(i+2) = F(i+1) + F(i) end
Either version is fine, but you have to choose one approach and be consistent. If you combine elements of both, you’ll get confused. I prefer the version in Listing [lst:fib_vec] that has F(i) on the left side of the assignment, so that each time through the loop it assigns the ith element.
Everything is a Matrix
In math (specifically in linear algebra) a vector is one-dimensional and a matrix is two-dimensional.
But in MATLAB, everything is a matrix (except strings). You can see this if you use the whos command to display the variables in the workspace. whos is similar to who, but it also displays the size of each value and other information.
To demonstrate, I’ll make one of each kind of value:
>> number = 5 number = 5 >> vector = [1 2 3 4 5] vector = 1 2 3 4 5 >> matrix = ones(2,3) matrix = 1 1 1 1 1 1
The built-in function ones builds a new matrix with the given number of rows and columns, and sets all the elements to 1. Now let’s see what we’ve got.
>> whos Name Size Bytes Class Attributes number 1x1 8 double vector 1x5 40 double matrix 2x3 48 double
According to MATLAB, all three are matrices. They have the same class, double, which means they contain double-precision floating-point numbers.
But they have difference sizes: the size of number is 1x1, which means it has 1 row and 1 column; vector has 1 row and 5 columns; and matrix has 2 rows and 3 columns.
So, you can think of your values as numbers, vectors, and matrices, but in MATLAB they are all matrices.
Yet another use of loops is to search the elements of a vector and return the index of the value you’re looking for (or the first value that has a particular property).
For example, the loop in Listing [lst:vec_search] finds the index of the element 0 in X:
for i=1:length(X) if X(i) == 0 ans = i end end
A funny thing about this loop is that it keeps going after it finds what it’s looking for. That might be what you want; if the target value appears more than one, this loop provides the index of the last one.
But if you want the index of the first one (or you know that there is only one), you can save some unnecessary looping by using the break statement.
for i=1:length(X) if X(i) == 0 ans = i break end end
break does pretty much what it sounds like. It ends the loop and proceeds immediately to the next statement after the loop (in this case, there isn’t one, so the code ends).