Maple для студентов физиков. Часть 1. Учебное пособие
.pdf
Глава 9. Программирование: логика, циклы, процедуры
Рассмотрим внимательно результаты исполнения этой команды, чтобы выяснить их смысл.
Отметим, что and, or и not можно использовать для комбинирования логических операторов, как ниже:
-2<=x and x<=-1.
Есть еще нюансы, которые можно увидеть, посмотрев ?if и ?boolean.
Третьим элементом в if является набор исполняемых операторов. В примере выше – это просто числа -1, 0, 1, хотя годится любое синтаксически правильное выражение. Например, можно построить функцию, которая принимает одно значение для отрицательных чисел, а другое – для положительных чисел:
>g:=x-> if x<0 then 1/(1+x^2) else cos(x) end if;
Проверьте, что в ней нет ошибок
>g(-1.5);g(2.5);
Посмотрите, что получится, если затребовать
> g(Pi);
Вамнадоуметьинтерпретироватьтакиеошибки, которыевыбудете получать время от времени. Машина говорит, что устала вычислять g, но когда в конце концов выполнит вычисления, одно из Boolean выражений окажется невозможно вычислить. Это получается, потому что Pi не является истинным числом в Maple, поэтому получается, что мы запрашиваем сравнение числа 0 и не-числа Pi. Pi в Maple – это более идея, чем число. Ту же самую ошибку получите, если попытаетесь вычислить g(a), где a еще не имеет численного значения
> g(a);
Проблему с Pi можно исправить, применив evalf(Pi) для получения численного значения:
> g(evalf(Pi));
Теперь нарисуем нашу функцию и посмотрим на нее
181
Maple для студентов физиков
> plot(g(x),x=-10..10);
Опять не та логика! Что же не так?
Конечно, с таким синтаксисом Maple не может нарисовать g(x) с оператором if. В команде plot при передаче x в g, x, очевидно, еще не число. Чтобы разобраться, посмотрим, что делает Maple с нашим оператором g:=x->... (см. выше): он вставляется в процедуру (подробнее об этом позже). Maple строит эту процедуру в «операторном представлении», означающем, что вы не можете применить для команды plot g(x),x=-10..10, вы только в записи пропускаете x, вроде того, как это сделано здесь:
> plot(g,-10..10);
Его можно продифференцировать с помощью команды D, как ниже:
> D(g);
Но если попытаетесь проинтегрировать, получите неразрешимую ошибку:
> int(g(x),x=-2..2);
Эта сложность является причиной того, что синтаксис if-then-else- end if не очень удобен для определения функций в Maple. Но кусочные функции, вроде этой, очень важны, поэтому нужен «чистый» способ работы с ними.
К счастью, есть в Maple команда piecewise, которая именно для этого и используется. Используем piecewise для переопределения функции g(x)
> g:=x->piecewise(x<0, 1/(1+x^2),x>=0, cos(x));
Теперь это действительно функция, которую можно построить как функцию
> plot(g(x),x=-5..5);
интегрировать как функцию,
> int(g(x),x=-5..5);
182
Глава 9. Программирование: логика, циклы, процедуры
и дифференцировать как функцию
> diff(g(x),x);
Поэтому такой путь построения кусочных функций лучше, чем if-then-elif-end if, но они, в основном, используются внутри циклов и процедур, о которых кратко поговорим ниже:
Задача 8.1
Используйте кусочную конструкцию Maple для построения функции, которая вычисляет так называемый кубический β-сплайн и строит его на отрезке t = -4..4. Функция B(t) определяется так:
(2 t)3 , если t в диапазоне -2..-1 6
1 (1 t) 3 (1 t) 3 3(1 t) , если t в диапазоне -1..0 6
1 (1 t) 3 (1 t) 3 3(1 t) , если t в диапазоне 0..1 6
(t 2)3 , если t в диапазоне 1..2 6
Если t вне области -2..2, B(t) = 0.
Вы обнаружите, что если надо указать область с границами, к примеру, от -1 до 0, придется комбинировать два неравенства, т. е. b<a<c.
В Maple это делается с помощью двух разных условий: неравенства и их сочетания с помощью and, вот так: b<a and a<c.
Если функция определена, нарисуйте ее график между -4 и 4.
Задача 8.2
Проинтегрируйте B(t) в интервале -3..3. Нарисуйте его первые три производные в интервале -3..3.
Задача 8.3
Эта задача – пример того, что piecewise не будет работать правильно и лучше применять if...end if.
183
Maple для студентов физиков
Примените if..endif для построения графика синуса от –2 ..2 , в котором максимумы/минимумы обрублены на высоте/глубине 0.9/-0.9 соответственно. ДляэтогобудетудобнакомандаMaple signum, и ваш старый друг evalf. Обратите внимание, что вместо применения логики для горизонтали (по x), как в примере для piecewise, вам надо применять логику в вертикали (по y).
Циклы: for, do, end do, while и break
В цикле выполняются многие команды Maple: sum, численное интегрирование, fsolve, численное решение дифференциальных уравне-
ний dsolve(...type=numeric) и мн. др.
Вы видели пример самостоятельно составленных циклов в процедуре трехмерного интегрирования в разделе «Расчеты» трехкратных интегралов и в разделе «Дифференциальные уравнения», раздел «Стрельба». Если Maple не должен понимать, что вы хотите сделать, вам понадобится написать собственный цикл. Чтобы разговор был более конкретным, напишем собственный цикл для суммирования квадратов целых чисел от 1 до 100. Команда Maple sum делает это так
> sum(i^2,i=1..100);
Внутреннее содержание этой команды – это цикл. Сделанный вручную цикл должен будет работать так же.
Цикл суммирования
Сначала вы должны решить, где должен храниться ответ, и затем присвоить этой переменной 0:
>answer:=0;
Вэтой переменной будут накапливаться результаты последовательного суммирования квадратов целых чисел от 1 до 100. Далее пишется обычный цикл для суммирования в синтаксисе Maple for..from.. to..do..end do. Учтите, что do означает «начало цикла», end do означает «конец цикла».
>for i from 1 to 100 do
184
Глава 9. Программирование: логика, циклы, процедуры
>answer:=answer + i^2;
>end do;
(см выдачу в отдельном листе). Может, этой информации много, но она вам понадобится, когда цикл не будет работать по неизвестной причине и надо будет искать ошибку. Чтобы убрать избыточную информацию, поставьте после конца цикла end do двоеточие, а не ;, а после цикла вызовите answer:
>answer:=0;
>for i from 1 to 100 do
>answer:=answer + i^2;
>end do:
>answer;
Аесли понадобится суммировать нечетные числа с 1 до 99 ? Вам надо начать с 1 и идти с шагом 2 до 99. Для этого применяется by в команде:
>answer:=0;
>for i from 1 by 2 to 99 do
>answer:=answer + i^2;
>end do:
>answer;
Цикл с последовательной подстановкой
Бывает, что вам неизвестно до каких пор следует «крутить» цикл, и его прекращение происходит при определенном условии
Например: что произойдет, если вы будете вычислять косинус числа снова и снова. Пусть Maple сделает это 20 раз и покажет нам что происходит.
>x:=5.;
>for i from 1 to 20 do
Берем косинус от x, результат заносим в него же и повторяем
>x:=cos(x);
>end do;
185
Maple для студентов физиков
Результат сходится к решению уравнения cos(x) = x. Но 20 шагов явно недостаточно, чтобы получить 10 правильных знаков. Для получения приемлемой точности, например 1e-8, надо построить циклы: выберите начальное значение x и начальное значение «предыдущего значения» xold
> x:=5.;xold:=0;
«Крутите» цикл while до тех пор, пока |x-xold|>1e-8 (вот почему нам нужно начальное значение xold).
Замечание: прежде чем начинать выполнять цикл while, прочтите команды и комментарии ниже
> while abs(x-xold)>1e-8 do
во временную переменную tempx заносите вычисленное значение cos(x)
> tempx:=cos(x):
текущее значение х заносите в xold – чтобы иметь возможность сказать, когда надо выходить из цикла
> xold:=x:
в х заносите новое значение х (называвшееся tempx)
>x:=tempx;
>print(x); # print the new x each iteration
Возврат на начало и повторение вычислений
> end do: # подавление печати столбца
Это называется последовательным интегрированием и часто применяется в машинных расчетах. Посмотрите внимательно на структуру цикла, в особенности на то, когда вычисляется каждая переменная и где она хранится (эти приемы вы уже применяли раньше, и они могут пригодиться в дальнейшем).
Есть две часто используемых разновидности циклов. В задачах вы потренируетесь работе с ними. Для справки – см. ?for.
186
Глава 9. Программирование: логика, циклы, процедуры
Задача 8.4
Напишите цикл, вычисляющий разложение косинуса в степенной
|
n |
|
|
|
|
|
|
|
|
|
|
n |
|
|
|
|||||
2 |
|
x |
||||
ряд: cos(x) |
( 1) |
|
|
для нечетных n. Вне цикла задайте значение |
||
n! |
|
|
|
|||
n 0 |
|
|
|
|
||
х, используя by для получения нечетных номеров и продолжайте цикл, пока значение последнего добавляемого в сумму члена, не станет меньше чем 1e-8. Для этого нужен цикл со сложением – см. начало раздела про цикл суммирования.
Задача 8.5–8.6
См. вторую часть Пособия.
Задача 8.7 – Метод секущих
Этот цикл всегда используется в вычислительной физике. Метод секущих применяется для решения сложных уравнений с одной переменной. Кстати, внутри команды fsolve применяется нечто подобное. Это также используется в дифференциальных уравнениях в Главе 8.
Идея метода
Пусть надо решить относительно х (сложное) уравнение вида f(x) = 0. Метод секущих начинается с двух относительно близких величин x1 и x2, значения которых «угаданы» заранее (как – это отдельная большая тема), из которых вычисляются f1 = f(x1) и f2 = f(x2).
Уравнение прямой, проходящей через эти две точки записывается
так: y f2 (f2 f1 )(x x1 ) . Но эта формула является аппроксимацией x2 x1
функции f(x) прямой линией. Ее можно применить для получения x, являющегося приближенным решением сложного уравнения. Уравнение (прямой) нужно решить и получить значение x, при котором y = 0, назвать его x3, и оно станет следующим приближением к точному решению.
>restart;
>Eqline:=0-f2=(f2-f1)/(x2-x1)*(x-x1);
>x3:=solve(Eqline,x);
187
Maple для студентов физиков
Это хорошее алгебраическое выражение, но нехорошее численное, поскольку при приближении к корню избранный способ выбора дает близкие значения x1 и x2; f1 и f2. В результате при вычислении x3 получится нечто похожее на деление 0/0. В арифметике с плавающей точкой это вызовет затруднения, поэтому лучше несколько изменить
формулу:
x3 x2 f2 (x2 x1 ).
С ней будем получать уточненное значение х3 , добавляя небольшую величину к предыдущей и не получая при этом проблем. В ней малы (x2 – x1) и (f2 – f1), поэтому снова получается /0, но значение f2 в числителе тоже мало, поскольку мы близки к f(x) = 0. В итоге получа-
ется нечто вроде 02 , тоже малое. 0
В Maple есть обучалка «Calculus – Single Variable», которая красиво анимирует этот метод. Посмотрите.
Задание
Напишите цикл для решения уравнения tan(x) – 2x = 0 для корня вблизи x = 1. (Сделайте свой цикл похожим на цикл с последовательной подстановкой.) В цикле предусмотрите выход по условию f2 = f1 по достижении приемлемой точности (в Maple это обычно 10 значащих цифр; см. Maple help, Digits) Это убережет вас от 0/0. Делать этот цикл с while трудно, но можно, если применить коман-
ду break.
Пример работы с break: (глупый).
Пусть цикл идет от 1 до 100, но вам надо выйти из него, когда i =20:
>for i from 1 to 100 do
>if i=20 then break end if;
>end do;
Обратите внимание, что после выхода из цикла i имеет то самое значение, которое было у нее в момент выхода.
> i;
188
Глава 9. Программирование: логика, циклы, процедуры
Вы можете применить это в вашем цикле для метода секущих. Для проверки необходимости такого применения сделайте так: сначала примените while; повторяя вычисления пока |f2| не станет <= 1e-14 , но при этом деление на 0 станет возможным, а затем поставьте команду break для защиты вашего цикла.
Процедуры: подключение к работе циклов и логики
Возможно, что вы уже поняли, что циклы и логика – мутное дело. Они занимают много места на рабочем листе и повторная работа с ними требует каких-то дополнительных действий, например, курсором. Эти действия можно автоматизировать, поместив их в нечто, что работает как функция и вам останется только задавать ей значения и получать ответ. Структура, которая делает это в процедуре называется командой proc.
Вот пример написания процедуры. Ее основная структура:
> restart;
Присвоение процедуре имени и определение списка ее аргументов
> f:=proc(x,y)
Объявление имен локальных переменных – тех которые будут использоваться только внутри процедуры.
> local a,b,z;
Объявление глобальных переменных, тех которые будучи объявлены вне процедуры, (нужны) для использования внутри нее.
> global d;
Теперь запишем операторы Maple, которые выполнят работу. В данном случае для расчета значения функции z мы используем переменные:
локальную a, глобальную d и заданные x и y и
z – локальную переменную (в ней – результат вычислений).
189
Maple для студентов физиков
Откуда Maple знает какую величину надо возвращать? Возвра-
щаемая величина – это последняя величина, вычисляемая в процедуре.
>a:=3.;b:=17.;
>z:=a*b*x*y*d; # last value
>end;
Дадим значение глобальной переменной d
>d:=31.;
>f(1,2);
Для иллюстрации того, как работает процедура, ниже показано вычисление косинуса угла в градусах.
>restart;
>cosdeg:=proc(theta)
>local phi,answer;
>phi:=theta*Pi/180.;
>answer:=cos(phi);
>end;
Проверим это
> yy:=cosdeg(45.);
Процедура – это написанная вами программа, поэтому часто случается так, что она не работает. (К сожалению, это правда.) Для отслеживания ошибок вам придется посмотреть, что происходит внутри процедуры. Команда Maple trace покажет вам нужные для сведения.
> trace(cosdeg);
и затем выполните нечто подобное этому
> cosdeg(45);
Когда все заработает правильно, и вам уже не понадобятся промежуточные данные, напишите
> untrace(cosdeg);
190
