Понятие об управляющих структурах.

Как известно, в любом языке программирования, и MATLAB здесь не является исключением, имеются специальные управляющие конструкции, позволяющие задать последовательность выполнения команд в программах. Таким конструкции называют операторами управления и задают с помощью зарезервированных ключевых слов.

Прежде рассматривались лишь достаточно простые программы, в которых все действия выполнялись последовательно. Вместе с тем, для реализации более сложных алгоритмов требуется составлять такие программы, где определенные команды выполняются в зависимости от определенных условий, либо выполняются в цикле, который запускается указанное число раз, либо завершается при выполнении заданного условия.

Очевидно, что в таких ситуациях не обойтись без использования специальных операторов управления, таких как, в частности, операторы цикла for и while, условный оператор if, переключатель switch...case, конструкции try...catch, а также операторы break, continue и return. Указанные операторы можно использовать как в файл-программах, так и в файл-функциях.

Операторы цикла.

Цикл – это процесс повторного выполнения группы инструкций, составляющих тело цикла. Количество выполнений команд можно либо задать заранее, либо определить в процессе выполнения программы. В зависимости от способа определения условия останова (окончания циклических повторений) различают два вида операторов цикла в M-языке: если число выполнений инструкций известно, то используется цикл for (своеобразный аналог цикла do в языке программирования FORTRAN), если же известно лишь условие продолжения цикла, но неизвестно количество его повторений, то применяется цикл while. Операторы цикла можно вводить как в интерактивном режиме (режиме калькулятора), вводя операторы непосредственно с клавиатуры, так и в текстах программ на M-языке.

Синтаксис цикла for имеет вид:

for var=выражение

Инструкции

end

где var – выбираемое программистом имя переменной (параметра, счетчика) цикла; выражение определяет набор возможных значений переменной var и, как правило, имеет вид a1:a2:a3, т.е. переменная цикла при каждом повторении цикла изменяется от начального значения a1 до конечного значения a3 с шагом a2 (если шаг a2 не задан, то по умолчанию он принимается равным 1 – по аналогии с языками программирования FORTRAN и Basic единичное приращение переменной цикла можно опускать), причем цикл завершается как только значение var превысит a3; если инструкций в теле цикла несколько, то они разделяются запятой (,) или точкой с запятой (;), их набор завершается оператором end.

Ниже представлен простейший пример использования цикла for. В результате выполнения программы

for x=1:3:10

y=x/4

end

будем иметь:

y =

0.2500

y =

y =

1.7500

y =

2.5000

В следующем фрагменте программы осуществляется вычисление частичной суммы ряда

Понятие об управляющих структурах. - student2.ru .

т.е. складывается 57 членов ряда

s=0

for k=1:1:57

s=s+1./k^2;

end;

В заголовке цикла (управляющем выражении) можно явно указать весь набор значений переменной цикла в виде вектор-строки, например:

for k=[2 5 7 8 11 15 25]

В данном случае цикл будет выполняться семь раз, при этом переменная k будет последовательно принимать значения 2, 5, 7, 8, 11, 15 и 25.

Весьма необычным, хотя и возможным является использование матриц в заголовке цикла:

A=[1 2; 3 4];

for k=A

Количество повторений такого цикла совпадает с количеством столбцов матрицы A, т.е. в рассматриваемом примере цикл повторится два раза. На каждом шаге цикла переменная цикла принимает значение очередного столбца матрицы, т.е. переменная цикла является вектор-столбцом. Так, например, приведенный ниже фрагмент программы вычисляет сумму длин векторов, являющихся столбцами матрицы A:

S=0; A=[1 2; 3 4];

for k=A

s=s+sqrt(k(1)^2+k(2)^2);

end;

Синтаксис цикла while имеет вид:

while Условие

Инструкции

end

где цикл выполняется до тех пор, пока истинно указанное Условие; набор выполняемых в цикле while инструкций, как и в цикле for должен завершаться оператором end; Условие – это любое распознанное MATLAB выражение, которое может включать операции сравнения и логические операции.

Ниже представлен простейший пример программы вычисления синуса 12 значений от 0 до 11 с помощью цикла while:

i=1; t=0;

while t<=11

y(i)=sin(t)

i=i+1;

t=t+1;

end

Рассмотрим более сложный пример вычисления частичной суммы ряда

Понятие об управляющих структурах. - student2.ru .

Будем иметь следующий фрагмент реализующей программы:

s=0; k=1; u=1;

while u>1.e-8

s=s+u;

k=k+1;

u=1./k^2;

end

Условием останова в данном случае является требование к складываемым элементам ряда быть больше некоторого заранее заданного числа (в данном случае это Понятие об управляющих структурах. - student2.ru ): как только очередное слагаемое станет меньше этого числа, условие, стоящее после ключевого слова while, становится ложным и суммирование прекращается.

Отметим, что в соответствии с указанным выше, представленный фрагмент кода, в котором тело цикла занимает несколько строк, также можно вводить с клавиатуры последовательно строка за строкой, при этом необходимо нажимать клавишу Enter каждый раз после ввода очередной строки. После ввода заголовка оператора цикла и нажатия клавиши Enter текстовый курсор перемещается на следующую физическую строку, однако знак строки при вводе (>>) не появляется. По сути, это означает, что MATLAB ожидает дальнейшего ввода с клавиатуры последовательности команд, составляющих тело цикла (эти инструкции могут занимать несколько физических строк командного окна). Текстовый курсор перемещается на следующую строку после нажатия клавиши Enter. После ввода ключевого слова end система MATLAB приступает к циклически повторяющемуся выполнению инструкций из тела цикла. По завершении этого процесса, длительность выполнения которого определяется объемом вычислительной работы, на следующей за циклом строке появляется знак >>.

Для досрочного прерывания циклов for и while используется команда break, размещаемая внутри тела цикла. Это позволяет размещать фактическое условие останова внутри тела цикла, а не в его заголовке. В таком случае в заголовке цикла можно писать всегда истинное выражение while 1. Если оператор break применяется во вложенном цикле, то он осуществляет выход только лишь из внутреннего цикла.

Оператор continue прерывает выполнение текущего шага цикла, т.е. позволяет перейти к следующей итерации в операторах циклов for и while, игнорируя все операторы, которые следуют за ним в теле цикла. Если оператор continue встречается во вложенном цикле, то осуществляется переход к следующей итерации основного цикла.

В системе MATLAB всюду, где это возможно, вместо операторов цикла следует применять соответствующие команды M-языка, предназначенные для обработки массивов, ввиду того, что при этом существенно сокращается время вычислений. Так, например, вместо фрагмента программы

k=0;

for x=0:0.1:100

k=k+1;

y(k)=sin(x);

end;

целесообразнее использовать операции с массивами

x=0:0.1:100;

y=sin(x);

Замену операторов цикла эквивалентными им по результату функциями M-языка принято называть векторизация кода [7,69-71,109,132,177].

Операторы ветвления.

К операторам ветвления относятся условный оператор if и оператор переключения switch, которые позволяют создать такие алгоритмы, в ко-

торых при заданных условиях выполняются те или иные блоки команд.

Рассмотрим условный оператор if, использующий ключевые слова if (если), else (иначе), elseif (иначе если), end (конец всей конструкции).

Наиболее простой синтаксис применения оператора if имеет вид:

if условие

Инструкции

end

где условие – произвольное выражение (чаще всего включающее в себя операции сравнения и логические операции), истинность или ложность которого понимается как отличие от нуля или равенство нулю (заметим, что в логических выражениях в системе MATLAB допускается использование массивов, причем в тех случаях, когда значением таких выражений является массив истинность условия наступает, когда истинны (не равны нулю) все элементы массива, ну а если хотя бы один элемент такого массива отличен от нуля, то условие считается ложным, ложным условие считается и при использовании пустого массива).

При выполнении простейшего фрагмента программы

A=[1 2; 3 0];

if A

b=1;

else

b=2;

получим, что переменная b примет значение 2, в силу того, что матрица A содержит один нулевой элемент, в результате чего все условие считается ложным. Отметим, что запись типа if A по своему действию полностью эквивалентна записи if A~=0 и записи if all(A(:)).

Если заданное условие является истинным, то Инструкции выполняются, если же условие является ложным, то Инструкции не выполняются, и программа переходит к выполнению команд, расположенных после слова end. Набор выполняемых инструкций всегда должен завершиться оператором end. В более общем случае синтаксис оператора if следующий:

if условие_1

Инструкции_1

elseif условие_2

Инструкции_2

elseif условие_3

Инструкции_3

...

else

Инструкции

end

Поясним, что в такой конструкции может быть много ветвей с ключевым словом elseif, при этом если справедливо условие условие_1, то выполняется набор команд Инструкции_1, если справедливо условие условие_2, то выполняется набор команд Инструкции_2 и т.д. Если же все эти условия оказываются ложными, то выполняются команды, расположенные после слова else. Отметим, что с одной стороны число ветвей elseif неограниченно, с другой – ветви elseif могут отсутствовать вовсе. Рассмотренный условный оператор завершается ключевым словом end.

Покажем, как используется конструкция if...else...elseif...end на примере простейшей файл-программы temperature (сохраненной в файле temperature.m):

function temperature(t)

if(t<=0)

disp('Морозная погода')

elseif and(t>0, t<=10)

disp('Холодная погода')

elseif and(t>10, t<=18)

disp('Прохладная погода')

elseif and(t>18, t<=25)

disp('Теплая погода')

else

disp('Жаркая погода')

end

Работоспособность приведенной файл-функции несложно проверить, задавая произвольные значения температуры в качестве аргумента функции temperature. Так, например, будем иметь:

>> temperature(-30)

Морозная погода

>> temperature(5)

Холодная погода

>> temperature(11)

Прохладная погода

>> temperature(21)

Теплая погода

>> temperature(27)

Жаркая погода

Рассмотренный оператор break не работает вне циклов for и while. В соответствующих случаях нужно использовать оператор return. Так, например, последний применяется совместно с условными операторами в теле файл-функций для реализации досрочного завершения функции и выхода из нее. В качестве характерного примера приведем файл-функцию factorial вычисления факториала целого положительного числа (сохраненную в файле factorial.m):

function res=factorial(n)

res=1;

if n==1

return

else

for i=2:n

res=res.*i;

end

end

Если входной параметр данной функции равен единице, то оператор return осуществляет досрочный выход из функции ввиду того, что правильный результат (res=1;) уже сформирован.

Если оператор return не используется, нормальное завершение функции наступает по исчерпании всех инструкций, размещенных в теле функции.

Нередко условные операторы совместно с оператором break, размещаемые внутри цикла, используются для досрочного выхода из цикла. Более того, иногда такое условие и вовсе является единственным, например:

prod=1; i=1;

while 1

prod=prod.*i

i=i+1;

if i>9

break

end

end

Очевидно, что в данном примере цикл без команды break, работающей совместно с условным оператором if, был бы бесконечным. Таким образом, цикл оказывается конечным, в результате выполнения фрагмента программы будет возвращено значение произведения целых чисел от единицы до девяти (факториал девяти).

Алгоритмы, в которых должен осуществляться множественный выбор, можно реализовать посредством оператора переключения switch, который является эффективной альтернативой использованию оператора if. Ниже представлен синтаксис переключателя switch (аналогом последнего в языке программирования FORTRAN является конструкция SELECT CASE):

switch выражение

case значение_1

Инструкции

case значение_2

Инструкции

case {значение_3, значение_4,...}

Инструкции

...

otherwise

Инструкции

end

В данной конструкции, прежде всего, вычисляется значение выражения выражение (это может быть скалярное числовое значение либо строка символов). Далее это значение сравнивается со значениями значение_1, значение_2, значение_3, значение_4 и т.д. (которые могут быть числовыми либо строковыми). Если найдено совпадение, то выполняются Инструкции, стоящие после соответствующего ключевого слова case. В противном случае выполняются Инструкции, расположенные между ключевыми словами otherwise и end. Строк со словом case может быть сколько угодно, но строка с ключевым словом otherwise должна быть одна. Конструкция {значение_3, значение_4,...} означает, что в строке с ключевым словом case может находиться массив ячеек (в таком случае оператор case будет истинным, если значение выражения выражение совпадает с любым из значений этого массива ячеек).

Заметим, что в случае, когда выражение представляет собой строку символов, соответствующий оператор case будет истинным, если функция вида strcmp(выражение,значение) возвращает значение 1 (истина).

Следует указать на важную особенность переключателя switch в языке программирования MATLAB: если в переключателе switch выполнена одна из ветвей, то остальные ветви этого переключателя выполняться не будут, поэтому никакие дополнительные операторы, позволяющие избежать выполнения других ветвей в данном случае не требуются (в отличие, например, от языков программирования C/C++).

Приведенная ниже файл-программа seasons (сохраненная в файле seasons.m) демонстрирует работу переключателя switch:

switch lower(s)

case{'декабрь','январь','февраль'}

disp('Время года - зима')

case{'март','апрель','май'}

disp('Время года - весна')

case{'июнь','июль','август'}

disp('Время года - лето')

case{'сентябрь','октябрь','ноябрь'}

disp('Время года - осень')

otherwise

disp('Неизвестное время года')

end

Представленная программа позволяет определить, к какому времени года относится месяц, заданный в качестве значения переменной s (поясним, что функция lower(s) преобразовывает все символы заданной текстовой строки s к строчным). Если переменной s присвоить число либо строковое значение, которое не является названием месяца, то программа распознает его как неизвестное время года. Например, имеем:

>> s='август';

>> seasons

Время года - лето

>> s='ОктЯбрЬ';

>> seasons

Время года - осень

>> s='апрель';

>> seasons

Время года - весна

>> s='январь';

>> seasons

Время года - зима

>> s='125';

>> seasons

Неизвестное время года

Прочие операторы.

Помимо рассмотренных, в системе MATLAB, разумеется, предусмотрены также прочие специальные операторы, позволяющие, в частности, избежать ошибок в программах. В частности, рассматриваемая далее управляющая конструкция try...catch позволяет распознать различные ситуации, которые могут привести к сбою в программе (какой бы идеальной последняя не была, могут существовать условия, при которых возможно возникновение ошибок), и если они случаются, выполнить необходимые действия для предотвращения проблем (т.е. корректно выйти из нежелательных (исключительных, нежелательных) ситуаций).

Если в программе имеются команды, выполнение которых может привести к ошибочным результатам, эти команды следует переместить в конструкцию управления try...catch, называемую также «перехватчиком исключительных ситуаций» (или «обработчиком ошибочных ситуаций»).

Управляющая конструкция try...catch имеет следующий синтаксис:

try

Инструкции_1

catch

Инструкции_2

end

Представленная конструкция работает следующим образом. При обычных условиях выполняется только блок команд Инструкции_1, однако если при попытке выполнения этого блока возникает какая-либо исключительная ситуация (например, программа не может отыскать файл, к которому задано обращение, либо невозможно выполнение арифметической операции с заданными значениями, либо возникает нехватка памяти компьютера), управление переходит к группе команд Инструкции_2 (т.е. в блоке команд Инструкции_2 обычно задаются команды, которые необходимо выполнить при возникновении ошибки в блоке Инструкции_1 (это может быть вывод на экран предупреждающего соотношения, либо команды, позволяющие обойти данную ошибку и перейти к выполнению дальнейших действий в программе).

Приведенный ниже пример иллюстрирует использование конструкции try...catch в простейшей файл-функции, выполняющей перемножение двух матриц:

function MatMult(A,B)

try

X=A*B

catch

disp('Перемножение заданных матриц A и B невозможно')

end

Поясним, что в соответствии с правилами матричного исчисления, операция перемножения матриц является невозможной, если число столбцов первого сомножителя не равно числу строк второго сомножителя, и если в качестве аргументов приведенной файл-функции задать такие «несогласованные» матрицы, то возникнет ошибочная ситуация и управление будет передано блоку catch, в результате чего на экране монитора отобразится сообщение, заданное командой disp, как это показано ниже.

>> A=[6 5 4; 3 2 1];

>> B=[1 2 3; 4 5 6; 2 3 4];

>> MatMult(A,B)

X =

34 49 64

13 19 25

>> MatMult(B,A)

Перемножение заданных матриц A и B невозможно

Заметим, что на практике ситуации, в которых целесообразно использовать конструкцию try...catch возникают достаточно редко, однако ее применение, тем не менее, целесообразно с позиций повышения надежности программы (в худшем случае такая конструкция просто не сработает, не принеся никакого дополнительного вреда), особенно при наличии в ней потенциально опасных мест. Вместе с тем, попасть в catch-отсек, как правило, весьма не просто – система MATLAB в большинстве своих функций и операций обрабатывает ошибочные ситуации весьма надежно, так что необходимость в дополнительных обработчиках отсутствует.

Работа с файлами

Общие замечания.

Файлы, как правило, представляют собой именованные области внешней (дисковой) памяти, с которыми программы обмениваются информацией. Потребность в такого рода обменах возникает в самых разнообразных ситуациях. Так, например, к услугам внешней памяти приходится прибегать, записывая туда очередную порцию накопленных данных, когда объем оперативной памяти может быть недостаточен для хранения нужной информации. В другой ситуации приложение может воспользоваться своими же данными, записанными ранее на диск или полученнными в результате работы других программ. Следует отметить, что поставщиками или потребителями данных, с которыми программа, созданная в системе MATLAB, может вступать в контакт могут быть не только дисковые файлы, но и файлы-устройства (дисплей, принтер, плоттер, сканер, клавиатура, каналы связи и т.д.). Тем не менее, далее будем рассматривать в основном работу с дисковыми файлами, хотя, в целом, соответствующее обслуживание файлов-устройств осуществляется по аналогичной схеме.

Отмечая ключевые аспекты процесса обмена данными, следует указать, что работа с файлами ограничивается, в основном, тремя-четырьмя операциями:

– выделение ресурсов и приведение файла в состояние готовности к обмену данными (именно это скрывается за термином открыть файл);

– чтение (ввод из файла) или запись (вывод в файл) очередной порции данных;

– возврат выделенных ресурсов и завершение неоконченных операций (этому соответствует термин закрыть файл).

К числу наиболее значимых аспектов обмена информации необходимо отнести формат представления данных на внешнем носителе. В своем подавляющем большинстве почти все системы программирования (и система MATLAB в этом смысле никак не исключение) используют два формата данных – текстовые и бинарные (двоичные).

Текстовые или символьные данные состоят из строк, похожих на те, которые пользователи набирают при вводе с клавиатуры или видят на экране монитора. Для текстовых данных характерна переменная длина строки, завершающейся невидимым признаком конца. Кроме того, числовые данные в строках представлены в виде, ествественном для человека. По сути, это означает, что при вводе символьных данных служебные программы преобразуют числовую информацию во внутренний формат компьютера, а при выводе работают другие сервисные программы, которые, напротив, преобразуют данные из машинного формата в приемлимый для пользователя вид.

В силу переменной длины строк обмен с текстовыми наборами данных приходится проводить последовательно – строка за строкой. В самом деле, для того, чтобы определить, где в наборе данных размещается строка с заданным номером, пришлось бы перебирать байт за байтом все символы предшествующих строк.

Как правило, обмен информации, хранящейся в символьном наборе данных, существенно превышает длину той же информации в машинном формате (указанное относится в основном к данным числового типа). Так, например, число Понятие об управляющих структурах. - student2.ru в символьном представлении занимает 16 байт, тогда как соответствующий машинный эквивалент с таким же количеством значащих цифр требует 8 байт.

В свете вышеизложенного текстовое представление данных имеет все же целый ряд недостатков, среди которых, в частности, меньшая эффективность по объему использованной памяти, потребность в дополнительных затратах на преобразования между машинным и символьным форматами, возможность исключительно последовательного обмена между программой и внешним носителем. Тем не менее, очевидно, что главным преимуществом текстовых данных является ественность их восприятия человеком, причем представление указанных данных, по существу, не зависит от конкретного компьютера или операционной системы (это важно при передаче данных между различными вычислительными платформами).

Информация, которая хранится в бинарных наборах данных может иметь совершенно разную природу. Обмен информацией с бинарными наборами данных не требует каких-либо преобразований. В этой связи он выполняется быстрее и связан с меньшими объемами памяти. В отличие от текстовых файлов, обмен данных с бинарными файлами выполняется порциями заданной длины, поэтому в зависимости от природы информации, хранящейся в бинарных файлах, здесь имеется возможность прямого доступа к нужной порции данных. В частности, если файл предназначен для временного хранения информации, используемой лишь программой, и его содержимое не будет переноситься на компьютеры другого типа, предпочтения целесообразно отдавать бинарным файлам.

Наши рекомендации