Управление потоком: if, for, while
Базовые конструкции управления — и трезвый взгляд на то, когда их применять, а когда векторизовать.
В MATLAB блоки управления закрываются ключевым словом
end, а не фигурными скобками.
Условный оператор
Синтаксис if прост: условие без скобок (хотя скобки допустимы), ветки elseif и else, закрытие end. Условие — это логическое выражение; для скалярных условий используют && и || с коротким замыканием.
x = 7;
if x > 10
disp('большое')
elseif x > 5
disp('среднее')
else
disp('малое')
end
Вывод:
среднее
Цикл for
Цикл for пробегает по столбцам массива: переменная цикла принимает значения элементов. Чаще всего перебирают диапазон 1:n. Помните главный совет курса: если тело цикла можно выразить векторно — выражайте; for оставляйте для случаев, где итерации зависят друг от друга.
s = 0;
for k = 1:5
s = s + k; % накопление
end
disp(s) % 15
Вывод:
15
Цикл while
Цикл while повторяется, пока условие истинно. Он уместен, когда число итераций заранее неизвестно — например, в итерационных численных методах, где считаешь до сходимости. break досрочно выходит из цикла, continue переходит к следующей итерации.
n = 1;
while n < 100
n = n * 2; % удвоение
end
disp(n) % 128 — первое число >= 100
Вывод:
128
switch для дискретного выбора
Когда вариантов много, читабельнее switch. Он сравнивает значение с метками case; ветка otherwise ловит остальное. В отличие от C, «проваливания» между case нет — каждая ветка автономна.
Как работает под капотом
Условие if в MATLAB истинно, если все элементы массива ненулевые. То есть if v для вектора v эквивалентно if all(v(:)). Это частый источник скрытых багов: программист думает «если хоть один элемент…», а MATLAB проверяет «если все». Когда нужна логика «хотя бы один» или «все», явно пишут any(...) и all(...) — так код читается однозначно.
Стоимость итераций и предвыделение
Если цикл всё же необходим, его пишут грамотно, и главное правило — предвыделение памяти. Растущий внутри цикла массив (result(end+1) = ...) заставляет MATLAB при каждом шаге копировать весь массив в новое, большее место, превращая линейный по смыслу цикл в квадратичный по времени. Лекарство простое: заранее создать массив нужного размера через zeros, а в цикле только записывать в готовые ячейки. Редактор сам предупреждает об этой ошибке подчёркиванием. Второй приём — выносить из тела цикла всё, что не зависит от итерации: вычисленное один раз снаружи не нужно пересчитывать тысячи раз внутри. Эти две привычки делают неизбежные циклы настолько быстрыми, насколько это возможно на интерпретируемом языке.
Частые ошибки
- Закрывать блоки скобками
{}вместоend. - Ставить условие-вектор в
if, не понимая, что проверяетсяall. - Писать
whileбез изменения условия внутри — бесконечный цикл. - Использовать циклы там, где напрашивается векторизация.
Перебор не только чисел
Цикл for в MATLAB устроен гибче, чем кажется. Переменная цикла пробегает столбцы заданного массива, и это значит, что перебирать можно не только диапазон 1:n, но и столбцы матрицы, и ячейки cell-массива. Например, for c = M присвоит c по очереди каждый столбец матрицы M. Это иногда удобнее, чем индексировать по номеру. Тем не менее в большинстве учебных и инженерных задач перебирают именно диапазон индексов — это самая распространённая и понятная форма.
Короткое замыкание и защита от ошибок
Логические операторы && и || обладают коротким замыканием: второе условие вычисляется, только если первое не определило результат. Это не просто оптимизация, а способ писать безопасный код. Запись if n > 0 && v(n) > 5 сначала проверит, что индекс n положителен, и лишь затем обратится к v(n) — иначе при n = 0 произошла бы ошибка индексации. Поэлементные & и | так не умеют: они всегда вычисляют оба операнда. Поэтому в скалярных условиях if предпочитают именно сдвоенные операторы — они и безопаснее, и быстрее. А для непредвиденных сбоев существует конструкция try ... catch, перехватывающая ошибки, чтобы программа не прерывалась, а корректно их обработала.
Итоги
- Блоки закрываются
end; ветки —elseif/else. forидёт по столбцам,while— до условия;break/continueуправляют ходом.ifнад массивом проверяет «все ненулевые» — используйтеany/all.