Сделай Сам Свою Работу на 5

Управляющие структуры if, for, while, switch





Лабораторная работа № 3. Разработка программ. Синтаксис файлов-функций, управляющие структуры MATLAB

Должен ли инженер уметь программировать?

 

Вопрос этот закономерный. Индустрия программного обеспечения (software) предлагает для решения самых разнообразных задач уже готовые мощные программные комплексы. Это, например, рассматриваемый здесь MATLAB для математических вычислений, NASTRAN для задач строительной механики, CorelDraw для графических работ и так далее, и так далее. Так не лучше ли воспользоваться этими профессионально выполненными продуктами, а не заниматься кустарщиной.

Практика, однако, показывает, что полностью предусмотреть все возможные потребности пользователя, несмотря на громкие рекламные заявления, производителям программного обеспечения пока не удается. Более того, часто подтверждается наблюдение Джадда Д.Р. [1]: «Программное обеспечение, рассчитанное на широкий круг пользователей, оказывается непригодным для конкретных применений». Поэтому в любом КБ, несмотря на оснащенность современными программными средствами, сотрудникам то и дело приходится составлять собственные программы.



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

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

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



В практике любого инженерного подразделения подобные задачи возникают регулярно. Кстати и в упомянутых ранее программных продуктах их создатели предоставляют возможность пользователю дополнить уже имеющиеся средства своими собственными программами. Например, в известной программе FEMAP этой цели служит встроенный язык программирования FEMAP Basic Scripting Language. Что касается MATLAB’а, то он оснащен мощным языком программирования, с которым вы ненавязчиво знакомитесь с первой страницы этого пособия (команды, файлы-сценарии, операции с массивами и т.д.).

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

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

Между тем уже давно программирование не считается уделом избранных. Если еще 40-50 лет назад считалось, что программировать, как писать стихи, дано не каждому, то уже с 70-х годов XX века программирование из разряда искусств перешло в разряд ремесел. То есть имеются определенные приемы и правила, следуя которым любой человек может написать действующую программу для решения достаточно сложных задач.



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

Тем не менее, хотя основные программные конструкции: подпрограммы, операторы цикла, условные операторы и т.п. сходны во всех языках программирования, они все-таки имеют и некоторые различия. Поэтому прежде чем перейти к технологии, коротко ознакомимся с основными инструментами: подпрограммами MATLAB’а – М‑функциями и управляющими структурами – if, for, while, switch.

 

М-файл – функция

 

Ранее вы уже встречались с программированием в MATLAB’е, когда познакомились с М-файлами – сценариями (script files). Используя только файлы-сценарии, можно решать достаточно сложные задачи. Однако, у файлов-сценариев имеются и существенные недостатки.

Рассмотрим вновь учебный пример из первого занятия: вычисление гипотенузы прямоугольного треугольника (рис.3.1). Для решения этой задачи можно использовать такой script-файл:

 

% Script: длина гипотенузы

x = a^2 + b^2;

c = sqrt(x)

Сохраним этот файл под именем hyposcr.m (сокращение слов hypotenuse и script). Теперь посмотрим, как будет выглядеть фрагмент сеанса, если нам потребуется рассмотреть несколько треугольников:

 

>> a=3;

>> b=4;

>> hyposcr

c =

>> a=6;

>> b=3;

>> hyposcr

c =

6.7082

>> a=5.3;

>> b=2.1;

>> hyposcr

c =

5.7009

 

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

Гораздо более удобно использование другой разновидности М-файлов: файлов-функций. Создайте в редакторе следующий файл:

 

% Function: длина гипотенузы

function c = hypofun(a,b)

x = a^2 + b^2;

c = sqrt(x);

 

Сохраните его под именем hypofun.m. С использованием этого файла-функции рассмотренный ранее фрагмент будет выглядеть гораздо компактней.

 

>> c1 = hypofun(3,4);

>> c2 = hypofun(6,3);

>> c3 = hypofun(5.3,2.1);

Внешне файл-функция отличается от файла-сценария только одной строчкой ‑ первой. Она начинается с ключевого слова function. Далее следует имя переменной, в которую надо будет поместить результат вычислений. После знака = следует идентификатор, который придумывает автор функции (в данном случае – мы с вами). Это имя функции. Обратите внимание, что это же имя мы использовали для файла, в котором сохранили эту функцию. После имени функции в круглых скобках список входных параметров – аргументов функции. Вызов функции, созданной нами, осуществляется так же, как и вызов стандартных функций MATLAB’а – мы записываем имя функции, и в скобках задаем значения аргументов.

На этом примере уже можно отметить первое преимущество функций перед сценариями: здесь гораздо удобнее организована передача аргументов и возврат результата вычислений.

Механизм передачи данных имеет и более серьезные преимущества, чем простое удобство. Рассмотрим для иллюстрации следующую простую задачу (рис. 3.2): Требуется определить длину AD при заданных . Такие задачи вам приходилось решать на уроках физики в восьмом классе (определить перемещение точки при движении по заданной траектории). Попробуем решить эту задачу, сначала используя файл-функцию, а затем файл-сценарий:

 

 


С использованием функции

 

>> x=2;

>> a=4;

>> b=3;

>> AD = hypofun(a,b) + x

AD = 7

 

С использованием сценария

 

>> x=2;

>> a=4;

>> b=3;

>> hyposcr;

c =

>> AD = c + x

AD = 30


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

Оперативную память компьютера можно упрощенно представить в виде длинного ряда ячеек, в каждой из которых может храниться число. При использовании файла-сценария распределение памяти изображено на рис 3.3. При использовании сценария сначала последовательно выделяются ячейки памяти и в них заносятся значения переменных . Затем следует вызов сценария. Напомним, что сценарий выполняется построчно так, как если бы вы набирали его строки с клавиатуры. Первая же строка сценария (посмотрите на предыдущую страницу) проясняет причину ошибки. Оказывается, что мы использовали переменную для того, чтобы поместить в нее сумму квадратов катетов. А нужное нам значение (x=2) оказалось испорченным.


При использовании функций способ распределения памяти другой (рис.3.4)

Сначала, пока мы присваиваем переменным значения из командной строки MATLAB’а, никакой разницы нет. Однако при вызове функции картина принципиально иная. Прежде всего, отметим, что для переменных функции выделяется отдельная область памяти. Сначала выделяются ячейки для формальных параметров – переменных, перечисленных в круглых скобках в заголовке функции. Затем в эти ячейки заносятся значения фактических параметров – это значения переменных, либо выражений, которые указываются в круглых скобках при вызове функции.

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

Наконец, после того как функция будет выполнена и переменной-результату будет присвоено вычисленное значение, MATLAB выполняет заключительные операции. Сначала значение, находящееся в переменной ‑ результате функции, заносится во временную переменную, соответствующую операнду hypofun(a,b) в выражении

>> AD = hypofun(a,b) + x

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

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

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

 

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

 

% Function: Гипотенуза и площадь прямоугольного треугольника

function [c,S] = hypoarea(a,b)

x = a^2 + b^2;

c = sqrt(x);

S = a*b;

 

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

 

>> [g,S]=hypoarea(3,4)

g =

S =

 

В заключение параграфа о том, когда и зачем следует использовать М-функции.

1. Первое напрашивающееся и очень полезное применение. Если в ходе решения какой-то задачи вам очень часто приходится набирать одно и то же выражение, например

cos(x)^2*sin(x) – sinh(2*x)

имеет смысл создать функцию с каким-нибудь запоминающимся именем вроде

c2sh()

и использовать ее далее, экономя время и снижая вероятность ошибки при наборе с клавиатуры.

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

 

 

Управляющие структуры if, for, while, switch

 

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

Но вернемся к нашим программам. Попробуем составить программу решения квадратного уравнения . С первой попытки у меня получился такой М-файл

 

% Решение квадратного уравнения

function res = sqeq(a,b,c)

d = b^2 - 4*a*c;

res(1) = (-b-sqrt(d))/(2*a);

res(2) = (-b+sqrt(d))/(2*a);

 

Пробую решить с помощью этой программы уравнение .

 

>> sqeq(1,-3,2)

ans =

1 2

 

Правильно? Вроде бы да. Но давайте теперь попробуем решить другое уравнение:

 

>> sqeq(0,2,4)

Warning: Divide by zero.

> In sqeq at 4

Warning: Divide by zero.

> In sqeq at 5

ans =

-Inf NaN

 

Что же получается? Уравнение очевидно имеет корень , но MATLAB вместо того, чтобы выдать этот очевидный ответ, разразился шестиэтажной фразой. MATLAB, конечно, ни в чем не виноват. Это мы составили программу не лучшим образом, не предусмотрев в нем обработку нетривиальной ситуации ( ). С помощью оператора if (условного оператора) можно легко модифицировать нашу функцию sqeq следующим образом:

function res = sqeq2(a,b,c)

% решение квадратного уравнения

if a==0

res = -c/b;

else

d = b^2 - 4*a*c;

res(1) = (b-sqrt(d)) / (2*a);

res(2) = (b+sqrt(d)) / (2*a);

end % if a==0

 

Как нетрудно догадаться, в случае, если а=0, вычисляется единственный корень уравнения, в противном случае решается квадратное уравнение.

 

>> sqeq2(0,2,4)

ans =

-2

 

Конструкция if в общем случае имеет вид:

 

if условие-1

группа операторов

elseif условие-2

группа операторов

else

группа операторов

end

 

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

= = - равно

> - больше

< - меньше

и логическими операциями:

& - логическое И

| - логическое ИЛИ

Если в приведенном шаблоне выполняется первое условие, то исполняется первая группа операторов; если первое условие не выполняется, но выполняется второе – исполняется вторая группа операторов; наконец, если не выполняется ни одно из условий – исполняется последняя группа операторов, следующая за else.

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

 

Конструкция for также должна быть хорошо известна тем, кто знаком хотя бы с одним языком программирования. В наиболее простом варианте в MATLAB’е эта конструкция имеет вид:

 

for параметр-цикла = начальное-значение : конечное значение

тело-цикла

end

Цикл for применяется, когда требуется выполнить группу операторов заранее известное количество раз. Для MATLAB’а в этом цикле характерно использование двоеточия (:) при указании границ цикла, а также использование зарезервированного слова end в качестве ограничителя цикла.

Пример. Функция, вычисляющая скалярное произведение двух векторов

 

% Скалярное произведение векторов

function res = scpr (n,a,b)

% n - размерность векторов

% a(n), b(n) - вектора-сомножители

res = 0;

for i=1:n

res = res + a(i)*b(i);

end

 

Здесь используется стандартный прием накопления суммы. Пример работы этой программы:

 

>> a = [1 2 3];

>> b = [-1 0 1];

>> scpr(3,a,b)

ans =

 

В MATLAB’е есть возможность использовать шаг изменения параметра, отличный от единицы и даже использования в качестве параметра цикла векторов и матриц. Однако эти изощренные возможности, описанные в HELP’е, здесь использоваться не будут.

 

Цикл while используется, когда количество повторений цикла заранее неизвестно. Окончания цикла определяется проверкой некоторого условия.

 

while условие

тело-цикла

end

 

Пример. Функция, суммирующая элементы вектора до тех пор, пока не встретит первый неположительный элемент

 

function res=sumpos(n,v)

% Суммирование элементов вектора, до первого неположительного элемента

% n - размерность вектора

% v(n) - вектор

res = 0;

i = 0;

 

while v(i+1)>0 & i<n

i = i+1;

res = res + v(i);

end % while

 

В заключение рассмотрим оператор switch выбора одного варианта из нескольких:

 

switch выражение

case константа-1

операторы

case константа-2

операторы

...

otherwise,

операторы

end

 

При выполнении этого оператора сначала вычисляется выражение после слова switch. Затем полученное значение сравнивается с константами, стоящими после слов case. Если, например значение выражения совпадает со второй константой, то выполняется группа операторов после строчки case константа-2. Если же значение выражения не совпадает ни с одной из констант, выполняются операторы, следующие после слова otherwise.

Вообще-то в операторе switch крайней необходимости нет, ‑ то же самое легко можно записать с помощью сложного оператора if. Однако этот оператор в программе выглядит обычно более наглядно и понятно.

 

Задание

Написать m-функцию, выполняющую заданные вычисления. Придумать 3 набора входных данных для тестирования функции и написать m-файл – сценарий, обращающийся к функции и выдающий результаты, получаемые при ее вызове. В одном из наборов данных предусмотреть ситуацию, в которой требуемый результат не может быть получен (если такая ситуация в принципе возможна). Размерности матриц и векторов должны быть не менее 5.

 

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

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

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

4. Вычислить количество и среднее арифметическое элементов матрицы, значения которых лежат в интервале [a, b]. Выходные параметры – вычисленное количество, среднее значение и вектор-строка, содержащая все элементы, удовлетворяющие указанному условию, в порядке, как они встречаются при построчном проходе матрицы.

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

6. Для каждой строки матрицы вычислить сумму элементов, имеющих дробную часть, и количество таких элементов. Выходные параметры – вектор-столбец, содержащий вычисленные суммы, и вектор-столбец из количеств элементов с дробной частью.

7. Определить номер строки матрицы, имеющей максимальную сумму четных элементов. Выходные параметры – вычисленный номер строки и вектор-строка, представляющая собой соответствующую строку матрицы.

8. Определить среднее арифметическое элементов матрицы, имеющих нечетное значение. Выходные параметры – вычисленное значение и вектор-строка, содержащая нечетные элементы в порядке, как они встречаются при построчном проходе матрицы.

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

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

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

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

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

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

15. Найти в матрице строку с минимальной суммой четных элементов. Если таких строк несколько, то выбрать строку с наибольшим номером. Строки, не содержащие четных элементов, не рассматриваются. Выходные параметры – номер найденной строки и вектор-строка, содержащая элементы этой строки.

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

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

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

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

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

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

23. Определить номер строки матрицы, имеющей минимальную сумму нечетных элементов. Выходные параметры – вычисленный номер строки и вектор-строка, представляющая собой соответствующую строку матрицы.

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

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

 

 

 








Не нашли, что искали? Воспользуйтесь поиском по сайту:



©2015 - 2024 stydopedia.ru Все материалы защищены законодательством РФ.