I recently posted about a GOTCHA with the expression a < x < b in MATLAB and Matt's comments made me look to see if I had ever devoted a post to the behavior of all (or its companion any). So today I will explain how all works and why you need to take care when you use arrays for testing conditions in if and while statements. This is especially true if you do not use them with functions such as any or all since they can reduce expressions to scalar true and false values.
Sometimes I see code that was written assuming the expression for an if statement will be a scalar. It's possible to then be confused if the expression is an array. If you were to loop through each element in the expression (for example, by placing the if statement inside a for loop), then each element would be evaluated separately and the expression would only execute the statements contained in the if portion for nonzero (or true) expression elements. However, once you hand the array over as an entity to if, you should be aware that ALL elements must be true for the expression to be true, and for the if body statements to execute.
It's also possible that users think that the statements contained within the body of the if statement will only be executed for elements that were true in the expression controlling the if statement. This is also not true.
The important thing you need to know is this, quoted from the MATLAB documentation.
"An evaluated expression is true when the result is nonempty and contains all nonzero elements (logical or real numeric). Otherwise, the expression is false."
This means that for an expression to trigger the execution of the body of an if statement, all of the elements in the expression be true. The following two code segments therefore give the same results.
if A > 0 doSomething end
if all(A(:) > 0) doSomething end
I will first show code that does not work on only the "relevant" elements of the if expression, and then show two ways to achieve the desired result.
Create an input array with integers between 0 and some maximum value.
intData = randperm(8); intData(randperm(8) > 5) = 0
intData = 7 0 3 0 5 0 1 2
Start with an output array of constant values, the same size as the input array.
outDataVec = 42*ones(size(intData));
Try replacing output values with 17 where the input array is nonzero.
if intData outDataVec = 17; end outDataVec
outDataVec = 42 42 42 42 42 42 42 42
This didn't change my output since the expression isn't true! Since that didn't work, let's try another way.
outDataVec1 = 42*ones(size(intData)); if intData outDataVec1(:) = 17; % see if we can just replace the "selected" elements end outDataVec1
outDataVec1 = 42 42 42 42 42 42 42 42
That didn't work either, since X(:) simply turns the array X into a column vector. And the input expression is still not all true.
outDataFor = 42*ones(size(intData)); for ind = 1:length(intData) if intData(ind) outDataFor(ind) = 17; end end outDataFor
outDataFor = 17 42 17 42 17 42 17 17
Of course, there's another better way to calculate the output represented by outDataFor, in a vectorized way, using logical indexing.
outDataArray = 42*ones(size(intData)); outDataArray(intData > 0) = 17
outDataArray = 17 42 17 42 17 42 17 17
Just to show that the for loop calculation matches the one using logical indexing.
ans = 1
Here are a couple of links to other posts that cover issues related to these topics.
Has the expression for an if or while statement bitten you? How did you figure it out and what did you do to resolve it? I'd love to see your thoughts here.
Get the MATLAB code
Published with MATLAB® 7.14