MATLAB & GNU Octave Module 4 – Logical arrays and control flow
Decisions: if, elseif, else and switch
Write if, elseif, else and switch blocks in MATLAB and Octave, see what if does with arrays and NaN, guard tests with && and ||, and compare text with strcmp.
What you will learn
- Write if, elseif and else chains whose tests run in the right order
- Predict what if does with an array, an empty array or NaN, and state the intent with any and all
- Use && and || to guard a test, and explain how they differ from & and |
- Write switch blocks with numeric, text and grouped cases
- Compare text with strcmp, strcmpi and ismember instead of ==
Before you start
What you’ll learn · Before you start
What you will learn
- Write if, elseif and else chains whose tests run in the right order
- Predict what if does with an array, an empty array or NaN, and state the intent with any and all
- Use && and || to guard a test, and explain how they differ from & and |
- Write switch blocks with numeric, text and grouped cases
- Compare text with strcmp, strcmpi and ismember instead of ==
Before you start
On this page
Six members of a frame have utilisation ratios from 0.42 to 1.12, and each must be labelled safe, near the limit or
over it, then sent to the check its type needs. That is a chain of if, elseif and else tests followed by a
switch on the type, and the order of the tests decides the answers: swap two of them and a member at 0.42 is
reported near the limit.
Here you write if chains and switch blocks, see what if does with an array, an empty array and NaN, use &&
and || to guard a test, and compare text with strcmp instead of ==.
if takes the first branch whose test is true
if runs its block when its condition is true. Each elseif adds a test that runs only when every test above it was
false, and else runs when none was true. This script labels one member by its utilisation u, the load on it
divided by the load it may carry, with this example’s own limits of 0.8 and 1.0, then picks the check for its type with
the switch of a later section:
% classify_load.m: the band of one member's utilisation u, and the check its type needs.
% Reads u and type from the workspace. The limits 0.8 and 1.0 are this example's own rule.
if u <= 0.8
band = 'safe';
elseif u <= 1.0
band = 'near the limit';
else
band = 'over the limit';
end
switch type
case {'beam', 'girder'}
check = 'bending';
case {'column', 'strut'}
check = 'buckling';
case 'tie'
check = 'tension';
otherwise
check = 'none: unknown type';
end
fprintf('%s, u = %.2f: %s, check %s\n', type, u, band, check); It reads u and type from the workspace, so the session sets them at the prompt and runs it for six members, then
runs classify_wrong.m, the same chain with its two tests swapped:
from session import prompt, version
version()
prompt("members.m") Output
# GNU Octave (aarch64-apple-darwin25.4.0) version 11.3.0
$ octave-cli --quiet
octave:1> u = 0.42; type = 'beam'; classify_load
beam, u = 0.42: safe, check bending
octave:2> u = 0.80; type = 'strut'; classify_load
strut, u = 0.80: safe, check buckling
octave:3> u = 0.95; type = 'girder'; classify_load
girder, u = 0.95: near the limit, check bending
octave:4> u = 1.12; type = 'tie'; classify_load
tie, u = 1.12: over the limit, check tension
octave:5> u = 0.60; type = 'Beam'; classify_load
Beam, u = 0.60: safe, check none: unknown type
octave:6> u = 0.56 / 0.7; type = 'beam'; classify_load
beam, u = 0.80: near the limit, check bending
octave:7> fprintf('%.17g\n', u)
0.80000000000000016
octave:8> u = 0.42; classify_wrong
u = 0.42: near the limit
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 bands_session.py
Step through the chain for three of the members:
The drawing shows the whole scene; its 6 steps are listed below.
Every step as text
- The girder, u = 0.95. The first test is u <= 0.8, and 0.95 <= 0.8 is false, so its branch is skipped and the next test runs.
- The second test. 0.95 <= 1.0 is true, so band becomes 'near the limit'.
- Straight to end. Once a branch has run, the rest of the chain is skipped. The else is never reached, and the program goes on after end.
- The beam, u = 0.42. The first test is true at once, so band is 'safe' and neither of the other branches is looked at.
- The tie, u = 1.12. Both tests are false, 1.12 <= 0.8 and 1.12 <= 1.0, so the else branch runs and band is 'over the limit'.
- Order decides. Every u that passes the first test would pass the second too, so the stricter test must come first. With the two swapped, as in classify_wrong.m, u = 0.42 came out as 'near the limit'.
Exactly one branch ran each time, the first whose test was true: the strut at 0.80 is safe because 0.80 <= 0.8 is
true. That is why the order matters. Every u that passes u <= 0.8 also passes u <= 1.0, so the stricter test
has to come first; classify_wrong.m tests u <= 1.0 first, and the beam at 0.42 came out near the limit. Put the
strictest test first, or write each test so that it excludes the others.
A limit also needs care when u is computed rather than typed. The sixth member, u = 0.56 / 0.7, printed as 0.80
and still came out near the limit: in double precision the division gives 0.80000000000000016, just above 0.8, as the
next line of the session shows. When a computed value can land on a limit, decide which side it belongs to with a
tolerance, as in the lesson on logical arrays.
else if is not elseif
Written as two words, else if opens a second if inside the else branch, and that if needs an end of its own.
The Octave manual warns that the elseif keyword must not be spelled else if.
Octave also accepts endif as the end of an if, but MATLAB requires end for every block, as the Octave wiki’s list
of differences records, so shared code writes end.
Checkpoint
Check: The first true branch, and the order of tests
An array condition is true only if every element is non-zero
A condition does not have to be one value. Given an array, if takes its branch only when the array is not empty and
every element is non-zero. The Octave manual writes if (matrix) as if (all (matrix(:))), with the empty case
excluded, and MathWorks says an expression is true when its result is non-empty and contains only non-zero elements.
The session tries the cases:
from session import prompt, version
version()
prompt("conditions.m", errors=1) Output
# GNU Octave (aarch64-apple-darwin25.4.0) version 11.3.0
$ octave-cli --quiet
octave:1> if [1 1 0], disp('taken'), else, disp('not taken'), end
not taken
octave:2> if [1 2], disp('taken'), else, disp('not taken'), end
taken
octave:3> if [], disp('taken'), else, disp('not taken'), end
not taken
octave:4> x = [3 -1 4];
octave:5> if x > 0, disp('all positive'), else, disp('not all positive'), end
not all positive
octave:6> if any(x < 0), disp('at least one negative'), end
at least one negative
octave:7> n = NaN;
octave:8> if n > 0, disp('positive'), else, disp('not positive'), end
not positive
octave:9> if n, disp('nonzero'), end
error: invalid conversion from NaN to logical
octave:10> if ~isnan(n) && n > 0, disp('positive'), else, disp('missing or not positive'), end
missing or not positive
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 conditions_session.py
Each condition of the session, and why it went the way it did:
| Condition | Branch taken? | Why |
|---|---|---|
if [1 1 0] |
no | one element is zero |
if [1 2] |
yes | every element is non-zero |
if [] |
no | an empty array is never true |
if x > 0, with x = [3 -1 4] |
no | the mask 1 0 1 has a zero |
if any(x < 0) |
yes | any reduces the mask to one value |
if n > 0, with n = NaN |
no | NaN > 0 is false, so else runs without a word |
if n, with n = NaN |
error | NaN cannot become true or false |
The rule is simple; the trouble is how if x > 0 reads. It looks like “if x is positive”, and for an array it means
“if x is not empty and every one of its elements is positive”. Say which you mean with all or any, and test
isempty on its own wherever an empty input can arrive.
NaN needs the same care. if n > 0 with n = NaN quietly took the else branch, so a missing value was handled as
“not positive”, while if n stopped with invalid conversion from NaN to logical. Test isnan first, as the last
line of the session did: if ~isnan(n) && n > 0.
Key idea
Never hand if an array and hope: write all(...) or any(...) for the question you mean, and test isempty and
isnan wherever empty or missing input can reach the condition.
Checkpoint
Check: Arrays, empty arrays and NaN as conditions
The short-circuit operators stop as soon as the answer is known
a && b is true when both sides are, and a || b when at least one is, like & and |, but they evaluate their
left side first and leave the right side alone once the result is settled. When the left side of && is false, the
whole is false whatever the right side says, so the right side never runs; when the left side of || is true, the
whole is true. This is
short-circuit evaluation: Working out a logical expression from left to right and stopping once its value is known: in a && b, b is not evaluated when a is false, and in a || b, not when a is true., and it makes guards possible: the left test makes
the right one safe to evaluate. This script guards an index with &&, then tries &:
% guard_empty.m: protect an index with && and see what & does instead.
x = [];
if ~isempty(x) && x(1) > 0
disp('&&: first value positive');
else
disp('&&: empty, or first value not positive');
end
if ~isempty(x) & x(1) > 0
disp('&: first value positive');
else
disp('&: empty, or first value not positive');
end
ok = ~isempty(x) & x(1) > 0; from session import prompt, run, version
version()
run("!octave-cli --no-init-all guard_empty.m")
prompt("shortcircuit.m") Output
# GNU Octave (aarch64-apple-darwin25.4.0) version 11.3.0
$ octave-cli --no-init-all guard_empty.m
&&: empty, or first value not positive
warning: Matlab-style short-circuit operation performed for operator &
warning: called from
guard_empty at line 8 column 4
&: empty, or first value not positive
error: x(1): out of bound 0 (dimensions are 0x0)
error: called from
guard_empty at line 13 column 1
[exit status 1]
$ octave-cli --quiet
octave:1> [1 0 1] & [1 1 0]
ans =
1 0 0
octave:2> [1 1] && 1
ans = 1
octave:3> [] && true
ans = 0
octave:4> [] || true
ans = 1
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 guard_session.py
Step through the condition of its first if:
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- An empty x. x is empty, as after a filter that kept nothing. The if statement asks ~isempty(x) && x(1) > 0.
- Left first. && works out its left operand first: ~isempty([]) is false.
- The right is skipped. With a false left side the whole condition is false, so && never evaluates x(1) > 0, the index that would fail on an empty x, and the else branch runs.
- x = [5 -2]. Now the left side is true, so && goes on to the right side. x(1) > 0 is 5 > 0, which is true, and so is the condition.
- Written with &. & evaluates both sides. Inside an if or while condition both programs short-circuit it all the same, Octave with a warning, but in ok = ~isempty(x) & x(1) > 0 the right side runs and fails on an empty x.
The first if printed its else message without touching x(1). The second, written with &, gave the same answer
with a warning: inside the condition of an if or a while, MATLAB short-circuits & and | too, as MathWorks’ &&
page notes, and Octave does the same for compatibility, warning Matlab-style short-circuit operation performed for operator &, as its manual describes. Outside a condition there is no such rule, and the last line of the script,
ok = ~isempty(x) & x(1) > 0, evaluated both sides and stopped with x(1): out of bound 0.
&& takes single values in MATLAB
MathWorks’ && page says each operand must evaluate to a scalar logical result, so [1 1] && 1 is not valid
MATLAB. Octave 11.3 accepted it and returned 1, and it treats an empty operand as false: [] && true gave 0 and
[] || true gave 1. Code that leans on this runs in Octave and fails in MATLAB, so reduce arrays with all or
any before they reach && or ||.
Checkpoint
Check: && and || as guards
switch runs the first case that matches, and only that one
When one value is compared with a list of fixed values, switch says it more plainly than a chain of elseif.
classify_load.m switches on type: each case names a value, or several in braces, and otherwise takes everything
else. MathWorks documents how a case matches: numbers with ==, text with strcmp, and a cell of values when any of
its elements matches. Step through it:
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- One value, many cases. switch compares the value of type with each case in turn. For text it compares with strcmp, which is case-sensitive.
- The first case. This case lists two names, and a cell case matches when any of its elements does. strcmp('girder', 'girder') is true, so check becomes 'bending'.
- No fall-through. Only the first matching case runs. The program goes on after end without trying the other cases, which is what both programs document.
- type = 'Beam'. With a capital B, strcmp finds no case equal to 'Beam', because 'B' and 'b' are different characters, so the otherwise branch runs.
- With lower. switch lower(type) compares 'beam' instead, and the first case matches again, as the session below shows.
Only the first matching case runs. MathWorks says MATLAB’s switch “does not fall through like a C language switch
statement”, and the Octave manual says only the first match is executed, so there is no break to forget and no
fall-through: In a C switch, running on into the statements of the next case when a case has no break. MATLAB and Octave never fall through: only the first matching case runs.. The session checks both points, then the cure for letter case:
from session import prompt, version
version()
prompt("switch_demo.m") Output
# GNU Octave (aarch64-apple-darwin25.4.0) version 11.3.0
$ octave-cli --quiet
octave:1> code = 2;
octave:2> switch code, case 0, disp('ok'), case {1, 2}, disp('warning'), case 2, disp('second match'), otherwise, disp('fault'), end
warning
octave:3> type = 'Beam';
octave:4> switch type, case {'beam', 'girder'}, disp('bending'), otherwise, disp('no case matched'), end
no case matched
octave:5> switch lower(type), case {'beam', 'girder'}, disp('bending'), otherwise, disp('no case matched'), end
bending
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 switch_session.py
code = 2 matched case {1, 2} and printed warning, and the later case 2 never ran. type = 'Beam' matched no
case, because strcmp is case-sensitive, and switch lower(type) matched again. Which of the two statements to use
depends on the test:
| Your test | Write | Why |
|---|---|---|
| One value against fixed numbers or names | switch |
one comparison per case, alternatives in braces |
Ranges, such as u <= 0.8 |
if and elseif |
a case compares with == or strcmp only |
| Tests on different variables | if and elseif |
switch looks at one value |
| Names in any letter case | switch lower(name) |
strcmp is case-sensitive |
End every switch with otherwise
classify_load.m only labels an unknown type. In real code, make otherwise stop with the value it did not expect,
such as error('unknown member type: %s', type), so that a typo in the data becomes a message instead of a quiet
default.
Checkpoint
Check: switch, cases and otherwise
Text is compared with strcmp, not character by character
== on text compares character codes position by position, as any element-wise operator does, so it returns a mask
and needs texts of the same length. strcmp compares complete texts, in the Octave manual’s words, and returns one
true or false. The session compares a few member names both ways:
from session import prompt, version
version()
prompt("text_compare.m", errors=1) Output
# GNU Octave (aarch64-apple-darwin25.4.0) version 11.3.0
$ octave-cli --quiet
octave:1> 'beam' == 'bean'
ans =
1 1 1 0
octave:2> 'beam' == 'girder'
error: mx_el_eq: nonconformant arguments (op1 is 1x4, op2 is 1x6)
octave:3> if 'beam' == 'bean', disp('same'), else, disp('different'), end
different
octave:4> strcmp('beam', 'girder')
ans = 0
octave:5> strcmp('Beam', 'beam')
ans = 0
octave:6> strcmpi('Beam', 'beam')
ans = 1
octave:7> ismember('strut', {'column', 'strut'})
ans = 1
octave:8> "beam" == "bean"
ans =
1 1 1 0
octave:9> class("beam")
ans = char
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 text_session.py
Line by line, with what each result means:
| Expression | Octave 11.3 gave | What it means |
|---|---|---|
'beam' == 'bean' |
1 1 1 0 |
a mask, one element per character |
'beam' == 'girder' |
an error: nonconformant arguments | 4 characters against 6 |
if 'beam' == 'bean' |
the else branch |
the mask has a zero |
strcmp('beam', 'girder') |
0 | different texts, and no error |
strcmp('Beam', 'beam') |
0 | letter case counts |
strcmpi('Beam', 'beam') |
1 | letter case is ignored |
ismember('strut', {'column', 'strut'}) |
1 | is the text one of these? |
MathWorks’ if page gives the same advice for MATLAB: use strcmp to compare character vectors, because == fails
when their sizes differ. if 'beam' == 'beam' does work, since every element of its mask is 1, which is how the habit
survives until two lengths differ.
Double quotes differ between the programs
In MATLAB, double quotes create a string, and MathWorks’ strcmp page notes that string arrays can be compared
with ==, one answer per string. In Octave 11.3, class("beam") printed char, and "beam" == "bean" gave the
mask 1 1 1 0. strcmp behaves the same in both programs, so it is the portable choice.
Checkpoint
Check: Comparing text
Practise: grade bands and units
Write these as scripts that read their input from the workspace, like classify_load.m, and run them at the prompt:
grade_band.m: frommarksout of 100, setbandto'O'for 90 and above,'A+'from 80,'A'from 70,'B+'from 60,'B'from 50,'C'from 40 and'F'below 40, the scheme of a fictional university. Run it for 90, 89, 80, 79, 40 and 39: you should get O, A+, A+, A, C and F.- Make it stop with
error('grades:badMarks', 'marks must be one number from 0 to 100')whenmarksis not one number from 0 to 100, testing in this order:~isscalar(marks) || marks < 0 || marks > 100. The||keeps an array away from the comparisons, somarks = [50 60]andmarks = 101must both stop. Then trymarks = NaN: it passes both comparisons and lands in F, so addisnan(marks)to the test. unit_factor.m: fromunit, setfactorwith aswitchwhose cases group a symbol with its name:{'N', 'newton'}gives 1,{'kN', 'kilonewton'}1000 and{'MN', 'meganewton'}1000000, andotherwisestops with an error. Do not uselowerhere: in the SI,Mis mega, 10^6, andmis milli, 10^-3, as the BIPM’s table of prefixes shows, so'mN'must never become a meganewton.
Then test your decisions. The questions follow your answers, and each one tells you why a choice holds or fails:
Practice that adapts to you
Practise this lesson
15 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Interview questions
Warm-up: what is the difference between & and && in MATLAB and Octave?
& is the element-wise and: it evaluates both of its operands and returns a logical array, so [1 0 1] & [1 1 0] is
1 0 0, and it is the operator for combining masks. && is the short-circuit and of two single true or false values:
it evaluates its left operand first and skips the right one when the left is false, so ~isempty(x) && x(1) > 0 never
indexes an empty x. Use & on arrays and && in if and while conditions. Two portability details: MathWorks
requires each operand of && to be a scalar logical result, while Octave 11.3 accepted [1 1] && 1; and inside a
condition MATLAB short-circuits & as well, which Octave does too, with a warning. | and || follow the same rules.
Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.
-
Fresher to mid
An input check reads if loads <= 0, error('invalid loads'), end. It let [5 0 7] through, let an empty vector through, and let [5 NaN 7] through. Explain each case, and rewrite the check so that it stops all three.
-
Mid to senior
A script that runs without errors in Octave 11.3 stops in MATLAB at if flags && n > 0, where flags is a 1-by-3 logical array. Explain the difference, give the portable fix, and name two other condition or comparison patterns that behave differently in the two programs.
Key takeaways
if,elseifandelserun the first branch whose test is true and skip the rest, so the strictest test comes first.- An array condition is true only when it is non-empty and has no zero element: write
alloranyfor what you mean, and testisemptyandisnanfirst. &&and||evaluate from left to right and stop once the answer is known, which makes guards such as~isempty(x) && x(1) > 0safe, while&outside a condition evaluates both sides.- MATLAB requires single true or false values on both sides of
&&and||; Octave 11.3 also accepted arrays, so shared code reduces them withallorany. switchcompares numbers with==and text withstrcmp, runs only the first matching case, groups alternatives in braces and should end withotherwise.- Compare text with
strcmp,strcmpiorismember:==compares characters and needs equal lengths, and double quotes make a string only in MATLAB.
Terms in this lesson
- fall-through
- In a C switch, running on into the statements of the next case when a case has no break. MATLAB and Octave never fall through: only the first matching case runs.
- short-circuit evaluation
- Working out a logical expression from left to right and stopping once its value is known: in a && b, b is not evaluated when a is false, and in a || b, not when a is true.
References
- GNU Octave manual: The if Statement (The Octave Project Developers)
- GNU Octave manual: The switch Statement (The Octave Project Developers)
- GNU Octave manual: Short-circuit Boolean Operators (The Octave Project Developers)
- GNU Octave manual: Searching in Strings (strcmp, strcmpi) (The Octave Project Developers)
- Differences between Octave and Matlab (GNU Octave Wiki)
- if, elseif, else: execute statements if condition is true (MATLAB) (MathWorks)
- switch, case, otherwise: execute one of several groups of statements (MATLAB) (MathWorks)
- Short-Circuit AND (MATLAB) (MathWorks)
- strcmp: compare strings (MATLAB) (MathWorks)
- Create string arrays (MATLAB) (MathWorks)
- SI prefixes (Bureau International des Poids et Mesures (BIPM))
Report a problem with this lesson
Kept only in this browser. Your Learn progress