Бинарные (инфиксные) операторы используются с двумя операндами, обычно размещаемыми по обе стороны от оператора. В ядро Maple 7 включено около трех десятков бинарных операторов. Основные из них перечислены в табл. 6.1.
Tаблица 6.1. Бинарные операторы
Обозначение |
Оператор |
+ |
Сложение |
- |
Вычитание |
* |
Умножение |
/ |
Деление |
** или ^ |
Возведение в степень |
mod |
Остаток от деления |
$ |
Оператор последовательности |
. |
Разделительная точка |
@ |
Оператор композиции |
@@ |
Повторение композиции |
, |
Разделитель выражений |
:= |
Присваивание |
. .. |
Задание интервала |
/ |
Разделитель выражений |
&* |
Некоммутативное умножение |
&<string> |
Нейтральный оператор |
|| |
Конкатенация (объединение) |
Примеры использования бинарных операторов:
Оператор композиции @@ может использоваться для создания сложных функций, содержащих цепные дроби:
А вот еще один пример применения этого оператора для составления цепного радикала и вычисления ряда таких цепочек в цикле:
Для комплексных чисел и данных, помимо упомянутых в предшествующем разделе, определен следующий ряд базовых функций:
argument — аргумент комплексного числа; 1 conjugate — комплексно-сопряженное число; Im — мнимая часть комплексного числа; Re — действительная часть комплексного числа; роlаг — полярное представление комплексного числа (библиотечная функция).Примеры применения:
В алгоритме вычисления ряда функций заложено сравнение результата с некоторым опорным значением. К таким функциям относятся:
abs — абсолютное значение числа; ceil — наименьшее целое, большее или равное аргументу; floor — наибольшее целое, меньшее или равное аргументу; frac — дробная часть числа; trunc — целое, округленное в направлении нуля; round — округленное значение числа; signum (х) — знак х (-1 при х < 0, 0 при х = 0 и +1 при х > 0).Для комплексного аргумента х эти функции определяются следующим образом:
tranc(x) = trunc(Re(*)) + I*trunc(IM(x)); round(x) = round(Re(.r)) + I*round(Im(x)); frac(x) - frac(Re(*)) + I*hac(Im(x)).Для введения определения значения floor(x) от комплексного аргумента прежде всего запишем а = Re(x) - fооr(Re(x)) и b = Im(x) - floor(Im(x)). Тогда flооr(x) = floor(Re(x)) + I*floor(Im(x)) + X, где
Наконец, функция ceil для комплексного аргумента определяется следующим образом:
cell(x) = -fооr(-х)
Примеры применения:
Функциональные операторы Maple-языка являются альтернативами функций и записываются в двух формах.
Нотация |
Запись оператора |
«arrow» (стрелочная) |
vars -> result |
«angle bracket» (в угловых скобках) |
<result | vars> |
Данные операторы могут использоваться для реализации подстановок. Например, запись х -> х^2 означает подстановку х*2 на место переменной х. Возможны и такие подстановки в множественной форме:
Функциональный оператор в Maple 7 часто используется для задания функций пользователя, которое будет рассмотрено несколько позднее.
Гиперболические функции представлены следующим набором:
sinh — гиперболический синус; cosh — гиперболический косинус; tanh — гиперболический тангенс; sech — гиперболический секанс; csch — гиперболический косеканс; coth — гиперболический котангенс.Примеры применения гиперболических функций представлены ниже:
На рис. 6.2 сверху представлены графики гиперболического синуса, косинуса и тангенса. По ним можно судить о поведении этих функций.
Рис. 6.2. Графики основных гиперболических и обратных гиперболических функций
ПРИМЕЧАНИЕ
В отличие от тригонометрических гиперболические функции не являются периодическими. Функция гиперболического тангенса имеет симметричную кривую с характерными ограничениями. Поэтому она широко используется для моделирования передаточных характеристик нелинейных систем с ограничением выходного параметра при больших значениях входного параметра.
Рис. 6.6. Графики функций Бесселя и гамма-функции
Для интерактивного ввода строк можно использовать функцию readline(filename), задав в качестве имени файла terminal или опустив имя файла. В этом случае ввод строки осуществляется с клавиатуры компьютера:
> s:=read1ine();
> Привет мой друг!
s:="Привет мой друг!"
ПРИМЕЧАНИЕ
Полезно обратить внимание на то, что запрос в ходе интерактивного ввода может быть сделан на русском языке (если установленный для запросов шрифт имеет символы кириллицы). Нужно также, чтобы и шрифт строки вывода содержал кириллицу, иначе в строке вывода будет типичная «абракадабра» — смесь непонятных символов.
Элементы векторов и матриц являются индексированными переменными, то есть место каждого элемента вектора определяется его индексом, а у матрицы — двумя индексами. Обычно их обобщенно обозначают как i (номер строки матрицы или порядковый номер элемента вектора) iij (номер столбца матрицы). Допустимы операции вызова нужного элемента и присваивания ему нового значения:
V[1] — вызов i-го элемента вектора V;
M[i, j] — вызов элемента матрицы М, расположенного на г-н строке в j-ы столбце;
V[i]:=x — присваивание нового значения х i-му элементу вектора V;
M[i,j]:=x — присваивание нового значения х элементу матрицы М.
Напоминаем, что строковые данные представляются совокупностью любых символов в обратных апострофах, например *Привет* или `2+2`. Для контроля объектов на принадлежность к строковым данным служит функция type с параметром string:
Из приведенных примеров видно, что контроль строкового типа осуществляется не очень строго, — в частности, единичные символы рассматриваются как строковые и без заключения их в апострофы. В строках могут быть символы кириллицы, но гарантии в правильности обработки таких символов нет — надо мириться с тем, что Maple — англоязычная программа и ее возможности в поддержке других языков ограниченны.
Логические (или булевы) операторы указывают на логическую связь величин (или выражений). Прежде всего они представлены рядом бинарных операторов, приведенных в табл. 6.3.
Таблица 6.З. Бинарные логические операторы
Обозначение |
Оператор |
< |
Меньше |
<» |
Меньше или равно |
> |
Больше |
>= |
Большее или равно |
- |
Равно |
О |
Не равно |
and |
Логическое «и» |
or |
Логическое «или» |
Конструкции с этими операторами, такие как х=у, возвращают логическое значение — константу true, если условие выполняется, и false, если оно не выполняется. Кроме того, к логическим операторам относится унарный оператор not — он представляет логическое «нет». Для возврата логических значений выражений с этими операторами используется функция evalb(условие), например:
Логические операторы часто используются в управляющих структурах программ, составленных на языке программирования Maple. Такое их применение мы рассмотрим позже.
Для создания нейтральных (задаваемых пользователем и в момент задания неисполняемых) операторов, определяемых пользователем, служит знак амперсанда — &. Синтаксис нейтрального оператора следующий:
&name
Имя оператора строится по правилам задания допустимых идентификаторов. Также в качестве имени может быть использована последовательность (один и более) специальных символов. В последовательности специальных символов не должно быть букв, цифр, подчеркивания, а также следующих символов:
& | () {} [] :: '' # <перевод строки> <пробел>
Максимальная длина имени — 495 символов. Нейтральные операторы могут быть унарными и бинарными. Примеры задания бинарного нейтрального оператора приведены ниже:
Ниже представлены наиболее распространенные целочисленные функции Maple 7, используемые в теории чисел:
factorial (n) — функция вычисления факториала (альтернатива — оператор !); iquo(a.b) — целочисленное деление а на b; irem(a,b) — остаток от деления а на b; igcd(a b) — наибольший общий делитель; lcm(a,b) — наименьшее общее кратное.Примеры применения:
В последних двух примерах применения оператора факториала полезно обратить внимание, что запись n!! означает лишь (n!)!, а не n!! = 2*4*6*..., то есть произведение четных целых чисел. Действие других функций очевидно.
Имеется ряд функций для работы со строками. Из них наиболее важны следующие:
lenght(str) — возвращает число символов, содержащихся в строке str; substring(str,a. .b) — возвращает подстроку строки str от а-го символа до b-го; cat(strl,str2....) — возвращает строку, полученную объединением строк strl, str2,... (альтернатива — оператор конкатенации в виде точки .); SearchText(s.str) — производит поиск подстроки s в строке str и при его успехе возвращает номер позиции s в строке str (при отсутствии s в str функция возвращает 0).Примеры применения этих функций (в виде продолжения ранее приведенных примеров) представлены ниже:
Эти функции дают достаточно средств для обработки данных строкового типа, которые можно применять не только для создания текстовых комментариев, но и для управления вычислительным процессом в программах.
Как и тригонометрические функции, гиперболические имеют свои обратные функции:
arcsinh — гиперболический арксинус; arccosh — гиперболический арккосинус; arctanh — гиперболический арктангенс; arcsech — гиперболический арксеканс: arccsch — гиперболический арккосеканс: arccoth — гиперболический арккотангенс.Примеры применения:
Графики обратных гиперболических синуса, косинуса и тангенса представлены на рис. 6.2 снизу.
К обратным тригонометрическим относятся следующие функции:
arcsin — арксинус; arccos — арккосинус; arctan — арктангенс; arcsec — арксеканс; arccsc — арккосеканс; arccot — арккотангенс.Примеры вычислений:
К этому классу функций принадлежит еще одна полезная функция: arctan(y.x) = argument(x+I*y)
Она возвращает угол радиус-вектора в интервале от -Pi до Pi при координатах конца радиус-вектора х и у (см. пример ниже):
Графики ряда обратных тригонометрических функций показаны на рис. 6.1.
Над матрицами с численными элементами можно выполнять разнообразные операции. Ниже приведены основные из них:
ПРИМЕЧАНИЕ
Рекомендуется внимательно изучить эти примеры и попробовать свои силы в реализации простых матричных операций. Мы вернемся к гораздо более серьезному описанию матричных операций и функций в дальнейшем.
Важное достоинство систем компьютерной алгебры, к которым относится и Maple 7, заключается в возможности выполнения аналитических (символьных) операций над векторами и матрицами.
Приведем примеры операций над векторами:
В этих примерах используется функция evalm(M), осуществляющая вычисление матрицы или вектора М.
ПРИМЕЧАНИЕ
Рекомендуется перед проведением символьных операций с векторами и матрицами очистить память от предшествующих определений с помощью команды restart. Если какие-то элементы векторов или матриц были ранее определены, это может привести к очень сильным искажениям вида конечных результатов. Очистка памяти устраняет возможность ошибок такого рода.
Мы уже неоднократно отмечали, что оператор % обеспечивает подстановку в строку ввода (или в выражение) последнего результата операции, Х% — предпоследнего и %%% — третьего с конца. Есть еще одна иногда полезная возможность проследить за ходом частных вычислений внутри документа — применение команды-функции history. В Maple V R5 это была библиотечная функция, которая требовала вызова из библиотеки. В Maple 7 такого вызова уже не требуется. Функция history (ехрr) или history() создает список переменных вида от, где индекс f = 1, 2, 3.... Этим переменным можно присваивать значения в диалоговом режиме и отслеживать результаты вычислений. Команда off;, вводимая после использования данной функции, завершает работу с ней. Ниже представлен диалог с применением функции history:
К сожалению, полученный результат и значения глобальных переменных 01 после завершения работы с данной функцией становятся недоступными, так что практической пользы от ее применения не так уж много. Разумеется, внутри блока history вы можете присвоить результат другой переменной и он сохранится (попробуйте это сделать сами). При каждом очередном применении функции history нумерация переменных 0i начинается с начала, так что какой-либо преемственности при использовании этой функции нет.
Функция history может применяться в качестве средства начальной отладки вычислений. Внутри фрагмента программы, заданного функцией history, можно задавать построения графиков. Например, при исполнении фрагмента программы:
будет построен график синусоиды. В целом работа с функцией history отличается не слишком высокой стабильностью, так что возможности этой функции пока остаются не слишком востребованными.
Для данных типа «множество» определены следующие бинарные операторы:
union — включает первый операнд (множество) во второй; intersect — создает множество, содержащее общие для операндов элементы; minus — исключает из первого операнда элементы второго операнда.В любом случае, в результирующем множестве устраняются повторяющиеся элементы. Действие этих операторов поясняют следующие примеры:
Напоминаем, что эти операторы заданы ключевыми словами. Обратите внимание на то, что в Maple 7 результат применения оператора union представлен членами, расположенными в довольно произвольном порядке.
Большие возможности для создания операторов с заданными свойствами предоставляет специальный оператор define. Он записывается в следующей форме:
define(oper, property1, property2. ._)
Здесь ореr — имя определяемого оператора, property!, property2 и т. д. — наименования свойств. В принципе, оператор define позволяет создавать операторы с новыми свойствами, которые отсутствуют у операторов и функций, встроенных в систему.
Могут быть указаны следующие свойства операторов:
unary — унарный оператор; binary — бинарный оператор; diff — дифференциальный оператор; linear — линейный оператор; multilinear — множественный линейный оператор; flat — ассоциативный оператор, для которого f(x/(y,z)) = f(f(x,y),z) = f(x,y,z); orderless — коммутативный симметричный оператор, такой что f(x,y) = f(y,x), antisymmetric — асимметричный оператор, такой что f(x,y) = -f(y,xc); zero — нулевой оператор (например, V:=Vector(5,shape=zero) задает вектор с 5 нулевыми элементами); identity — единичный оператор (например, M:=Matrix(3,3,shape=identity) задает единичную матрицу).Следующий пример задает линейный оператор L:
Для задания некоторых свойств операторов можно использовать уравнения и соотношения вида f(x)=value. Чтобы свойство выполнялось для всех аргументов (или некоторого класса аргументов), используется описание forall. Так, приведенный ниже пример задает оператор F, который вычисляет n-е число Фибоначчи (n > 2):
Обратите внимание на то, что соотношения fib(0)=l и fib(l)=l задают начальные значения целочисленного массива чисел Фибоначчи, которые нужны для реализации обычного итерационного алгоритма их нахождения, — напоминаем, что очередное число Фибоначчи равно сумме двух предшествующих чисел Фибоначчи.
Последний пример иллюстрирует применение системной функции time для определения времени, затраченного на вычисление значения функции fib(20). Это время задается в секундах. Нетрудно заметить, что даже для ПК с процессором Pentium II 350 МГц это время оказалось довольно значительным (более 3 с), поскольку каждое новое число Фибоначчи вычисляется заново.
Maple 7 имеет полный набор элементарных математических функций. Все они, кроме арктангенса двух аргументов, имеют один аргумент х, например sin(x). Он может быть целым, рациональным, дробно-рациональным, вещественным или комплексным числом. В ответ на обращение к ним элементарные функции возвращают соответствующее значение. Поэтому они могут быть включены в математические выражения. Все описанные здесь функции называются встроенными, поскольку они реализованы в ядре системы.
Как правило, если аргументом функции является фундаментальная константа, целое или рациональное число, то функция выводится с таким аргументом без получения результата в форме действительного числа с плавающей точкой. Например:
Нетрудно заметить, что есть и исключения из этого правила — например, на экране монитора ехр(1) будет выведено как константа е, а значение функции arcsin( 2) все же вычислено и результат получен как 1/6 от константы Pi. Вообще говоря, если результат выражается через фундаментальную математическую константу, то он будет вычислен и представлен ею. В противном случае функция с целочисленным и рациональным аргументом или с константой просто повторяется в строке вывода в установленном для этой строки формате.
Для получения подробной информации о некоторой произвольной функции <f> достаточно задать команду:
?<f>
Ввиду общеизвестности элементарных функций мы не будем обсуждать ни их свойства, ни допустимые для них пределы изменения аргумента.
Прежде всего надо обратить внимание на то, что векторы и матрицы хотя и похожи на списки, но не полностью отождествляются с ними. В этом можно убедиться с помощью следующих примеров, в которых функция type используется для контроля типов множественных объектов (векторов и матриц):
Однако, используя функцию преобразования данных convert, можно преобразовывать одномерные списки в векторы, а двумерные — в матрицы. Функция type используется в следующих формах:
type(V, vector) — тестирует аргумент V и возвращает true, если V — вектор, и false в ином случае; type(M,matrix) — тестирует аргумент М и возвращает true, если М — матрица, и false в ином случае.Здесь параметры vector и matrix используются для указания того, какой тип объекта проверяется.
ПРИМЕЧАНИЕ
Обратите внимание на то, что матрицы отображаются иначе, чем двумерные списки, без двойных квадратных скобок. Отображение вектора подобно отображению одномерного списка, поэтому здесь особенно важен контроль типов данных.
Часто возникает необходимость в интерактивном вводе математических выражений. Для ввода с запросом выражения используется функция readstat(promt), где promt — строка с текстовым комментарием. Пример ее применения дан ниже:
Альтернативой может стать ввод строкового выражения с последующим преобразованием его в математическое выражение с помощью функции parse:
Обратите внимание на то, что функция evaln не смогла вычислить строковое выражение `2+3` поскольку оно не является числовым типом данных. Однако функция parse преобразовала это выражение в числовое, что и привело к его вычислению.
Приведем еще ряд примеров выполнения символьных операций с одной матрицей:
Среди других функций для работы с матрицами полезно обратить внимание на функцию mар, которая применяет заданную операцию (например, функции дифференцирования diff и интегрирования int) к каждому элементу матрицы. Примеры такого рода даны ниже:
В результате возвращаются матрицы, каждый элемент которых представлен производной или интегралом. Аналогично можно выполнять над матрицами и другие достаточно сложные преобразования.
В дальнейшем мы продолжим изучение матричных функций и операций, включенных в пакеты Maple 7.
Ниже представлены примеры символьных операций, осуществляемых над квадратными матрицами одного размера:
Специальные математические функции обычно являются решениями линейных дифференциальных уравнений различного типа и выражаются в виде интегралов, не представимых через элементарные функции. Maple 7 имеет практически полный набор таких функций. Их представления можно найти в справочной литературе, а также в справочной базе данных Maple. В связи с этим ограничимся приведением названий наиболее важных специальных функций:
AiryAi (Bi) — функции Эйри; AngerJ — функция Ангера; bernoulli — числа и полиномы Бернулли; Bessel I (J, К, Y) — функции Бесселя разного рода; Beta — бета-функция; binomial — биноминальные коэффициенты; Chi — интегральный гиперболический косинус; Ci — интегральный косинус; csgn — комплексная сигнум-функция; dilog — дйлогарифм; Dirac — дельта-функция Дирака; Ei — экспоненциальный интеграл; EllipticCE (CK, CPi, E, F, К, Modulus, Nome, Pi) — эллиптические интегралы; erf — функция ошибок; erfc — дополнительная функция ошибок; euler — числа и полиномы Эйлера; FresnelC (f, g, S) — интегралы Френеля; GAMMA — гамма-функция; GaussAGM — арифметико-геометрическое среднее Гаусса; HankelHl (H2) — функции Ганкеля; harmonic — частичная сумма серии гармоник; Heaviside — функция Хевисайда; JacobiAM (CN, CD, CS, ON, DC, DS, NC, NO, NS, SC, SO, SN) - эллиптические функции Якоби; JacobiThetal (2, 3, 4) — дзета-функции Якоби; JacobiZeta — зет:функция Якоби; KelvinBer (Bei, Her, Hei, Ker, Kei) — функции Кельвина; Li — логарифмический интеграл; 1nGAMMA — логарифмическая гамма-функция; MeijerG — G-функция Мейджера; pochhammer — символ Похгамера; polylog — полилогарифмическая функция; Psi — дигамма-функция; Shi — интегральный гиперболический синус; Si — интегральный синус; Ssi — синусный интеграл смещения; StruveH (L) — функции Струве; surd — неглавная корневая функция; LambertW — W-функция Ламберта; WeberE — Е-функция Вебера; WeierstrassP — Р-функция Вейерштрасса; WeierstrassPPrime — производная Р-функции Вейерштрасса; WeierstrassZeta — зета-функция Вейерштрасса; WeierstrassSigma — сигма-функция Вейерштрасса; Zeta — зета-функция Римана и Гурвица. Ввиду большого числа специальных функций и наличия множества примеров их вычисления в справочной системе Maple 7 ограничимся несколькими примерами вычисления наиболее распространенных специальных функций.
По их подобию читатель может опробовать в работе и другие специальные функции.
На рис. 6.4 даны примеры применения ряда специальных функций. Обратите особое внимание на первый пример. Он показывает, как средствами системы Maple 7 задается определение функций Бесселя. Показано, что функции Бесселя являются решениями заданного на рис. 6.4 дифференциального уравнения второго порядка. Maple 7 способна вычислять производные и интегралы от специальных функций.
Операторы в Maple описывают операции по преобразованию данных, в частности выражений. Последние, в свою очередь, можно отнести к данным абстрактного типа. Могут быть описаны следующие типы операторов:
неопределенные (f); нейтральные (&); процедурные; функциональные; композиционные (@).Оператор относится к неопределенным, если он не был заранее определен. Такой оператор не выполняет никаких действий и просто повторяется в строке вывода:
> restar:f(1,2,а):
f(l,2,a)
Композиционные операторы (на базе знака @) мы уже применяли. Другие типы операторов рассмотрены ниже.
К степенным и логарифмическим относятся следующие функции системы Maple 7:
ехр — экспоненциальная функция; ilog10 — целочисленный логарифм по основанию 10 (возвращает целую часть от логарифма по основанию 10); ilog — целочисленный логарифм (библиотечная функция, возвращающая целую часть от натурального логарифма); n — натуральный логарифм; log — логарифм по заданному основанию (библиотечная функция); log10 — логарифм по основанию 10; sqrt — квадратный корень.Примеры применения:
Графики ряда алгебраических функций показаны на рис. 6.3.
Рис. 6.З. Графики ряда алгебраических функций
На рис. 6.3 показаны также графики синусоиды с экспоненциально падающей и нарастающей амплитудой. Читателю рекомендуется попробовать свои силы в построении графиков комбинаций различных функций.
В ядре Maple определены следующие тригонометрические функции:
sin — синус; cos — косинус; tan — тангенс; sec — секанс; csc — косеканс; cot — котангенс.Все эти функции являются периодическими (с периодом 2л, кроме тангенса и котангенса, у которых период равен л) и определены для действительного и комплексного аргументов. Примеры вычислений:
Многие свойства тригонометрических функций можно оценить, рассматривая их графики. Для построения таких графиков можно использовать функцию pi ot. На рис. 6.1 сверху показаны графики ряда тригонометрических функций.
Рис. 6.1. Графики ряда тригонометрических и обратных тригонометрических функций
Из графиков тригонометрических функций (рис. 6.1, сверху) хорошо видна их периодичность. Функция тангенса имеет разрывы, и ее значение в этих точках в пределе равно бесконечности. Поэтому для наглядного ее представления вместе с функциями синуса и косинуса (их экстремальные значения по модулю равны 1) приходится вводить ограничения на масштаб графика по оси у.
ПРИМЕЧАНИЕ
Обратите внимание на параметр color=black в функции построения графиков plot. Он задает построение всех графиков черным цветом, что сделано для более четкой печати их в книге. Если убрать этот параметр, то графики разных функций будут строиться с использованием разных цветов, что облегчит их различение. Другие способы выделения отдельных кривых будут описаны в дальнейшем при описании графических возможностей системы Maple 7.
Унарные операторы используются с одним операндом. Они могут быть префиксными, если оператор стоит перед операндом, и постфиксными, если он стоит после операнда. К унарным относятся семь операторов, приведенных в табл. 6.2.
Таблица 6.2. Унарные операторы
Обозначение |
Оператор |
+ |
Унарный плюс (префикс) |
- |
Унарный минус (префикс) |
; |
Факториал (постфикс) |
. |
Десятичная точка (префикс или постфикс) |
$ |
Последовательность (префикс) |
not | Логическое отрицание (префикс) |
&string | Метка (префикс) |
Примеры применения унарных операторов:
Операторы во входном языке и языке программирования Maple служат для конструирования выражений. Формально операторы представлены своими идентификаторами в виде специальных математических знаков, слов и иных имен. Операторы, как это вытекает из их названия, обеспечивают определенные операции над данными, представленными операндами.
Имеется пять основных типов операторов:
binary — бинарные операторы (двумя операндами); unary — унарные операторы (с одним операндом); nullary — нульарные операторы (без операнда — это одна, две и три пары кавычек); precedence — операторы старшинства (включая логические операторы); functional — функциональные операторы.Для просмотра операторов и их свойств можно использовать следующие команды:
> ?operators[binary];
> ?operators[unary];
> ToperatorsCnullary];
> ?operators[precedence];
> ?operators[functional]:
А для изучения примеров применения операторов нужно задать и исполнить команду:
> ?operators[examples];
Команда:
> Tdefine:
позволяет ознакомиться с функций define. С ее помощью можно определять новые операторы.
Зачастую необходимо циклическое повторение выполнения выражения заданное число раз или до тех пор, пока выполняется определенное условие. Maple 7 имеет обобщенную конструкцию цикла, которая задается следующим образом:
| for <name>| |from <exprl>| |to <expr3>| |by <expr2>| (while <expr4>| do Statement sequence> od;
Здесь name — имя управляющей переменной цикла, exprl, ехрr2 и ехрrЗ — выражения, задающие начальное значение, конечное значение и шаг изменения переменной name, ехрr4 — выражение, задающее условие, пока цикл (набор объектов между словами do и od) будет выполняться.
В ходе выполнения цикла управляющая переменная меняется от значения exprl до значения ехрr2 с шагом, заданным ехрrЗ. Если блок by <ехрr2> отсутствует, то управляющая переменная будет меняться с шагом +1 при ехргКехрг2. Это наглядно поясняет следующий пример:
> for i front 1 to 5 do printd) od;
1
2
3
4
5
В нем выводятся значения переменной i в ходе выполнения цикла. Нетрудно заметить, что она и впрямь меняется от значения 1 до значения 5 с шагом +1. Следующий пример показывает, что границы изменения управляющей переменной можно задать арифметическими выражениями:
> for i from 7/(2+5) to 2+3 do printd) od:
1
2
3
4
5
А еще один пример показывает задание цикла, у которого переменная цикла меняется от значения 1 до 10 с шагом 2:
> for i from 1 to 10 by 2 do printd) od: 1 3 5 7 9
8 этом случае выводятся нечетные числа от 1 до 9. Шаг может быть и отрицательным:
> for i from 9 to 1 by -2 do print(i) od:
9
7
5
3
1
Следует отметить, что если exprl>expr2 задать заведомо невыполнимое условие, например, ехрr1>ехрг2 и положительное значение шага, то цикл выполняться не будет. Цикл можно прервать с помощью дополнительного блока while <ехрr4>. Цикл с таким блоком выполняется до конца или до тех пор, пока условие ехрг4 истинно.
> for i from 1 to 10 by 2 while i<6 do print(i) od:
1
3
5
Таким образом, конструкция цикла в Maple-языке программирования вобрала в себя основные конструкции циклов for и while.
Есть еще одна, более специфическая конструкция цикла:
|for <name>| |in <exprl>| |whi1e <expr2>| do statement sequence> od:
Здесь exprl задает список значений, которые будет принимать управляющая переменная name. Цикл будет выполняться, пока не будет исчерпан список и пока выполняется условие, заданное выражением ехрг2. Следующий пример иллюстрирует сказанное:
> for i in [1.2,5,-1.7.12] do print(i) od;
1
2 5 -1 7
12 > for i in [1,2.5.-1,7.12] while i>0 do print(i) od:
1
2 5
В цикле этого вида управляющая переменная может меняться произвольно. Циклы могут быть вложенными. Это иллюстрирует следующий пример, создающий единичную матрицу на базе заданного массива М:
При профессиональной подготовке процедур пользователь должен предусмотреть их поведение при возможных ошибках. Например, если он готовит процедуру или функцию, вычисляющую квадратный корень из действительных чисел, то надо учесть, что такой корень нельзя извлекать из отрицательных чисел (будем, исключительно в учебных целях, считать, что комплексные числа в данном примере недопустимы).
Для контроля за типом данных обычно используются различные функции оценки и тестирования. При выявлении ими ошибки, как правило, предусматривается вывод соответствующего сообщения. Для этого используется функция ERROR:
ERROR(expr_1. expr_2. ...)
где ехрr_1, ... - ряд выражений (возможно, пустой). Наиболее часто ERROR выводит просто строковое сообщение об ошибке, например ERROR (`strings'). Полное сообщение об ошибке имеет вид:
Error, (in name) string. ...
Приведем пример процедуры, в которой предусмотрен вывод сообщения об ошибке при задании переменной х < 0:
> f := ргос (х) if x<0 then error "invalid variable x: XI". x else x*(l/2) end if end proc; f:= proc (x) if x < 0 then error "invalid variable x: %1" x else sqrt(x) end if end proc
> f(3.): 1.732050808
> f(-3.);
Error, (in f) invalid variable x: -3.
> lasterror;
"invalid variable x: %1" -3.
> lastexception;
f, "invalid variable x: %1", -3.
Эта процедура вычисляет квадратный корень из числа х. При х < 0 выводится заданное сообщение об ошибке. Еще раз обращаем внимание читателя на учебный характер данного примера, .поскольку вычисление квадратного корня (в том числе из комплексных и отрицательных действительных чисел) реализовано встроенной функцией sqrt.
Язык Фортран вот уже многие десятилетия используется для программирования вычислительных задач. Накоплены обширные библиотеки решения таких задач на Фортране. Почитателей этого языка Maple 7 порадует тем, что она позволяет готовить коды для программ на Фортране. Для этого вначале надо загрузить библиотечную функцию:
> with(codegen.fortran);
[fortran ]
После этого может использоваться функция fortran:
fortran(expr.filename=str.optimized)
Два последних параметра не обязательны при выводе выражения ехрr в форме, присущей языку Фортран:
> fortran(a*x*2+b*x+c);
t0 = a*x**2+b*x+c
> fortran(diff(x"n,x$2));
t0 = x**n*n**2/x**2-x**n*n/x**2
Параметр optimize позволяет генерировать оптимизированные коды:
> fortran(a*x*2+b*x+c.optimized);
t1 = x**2 t4 = a*tl+b*x+c
При этом вычислительный процесс строится так, чтобы минимизировать число арифметических операций.
Язык С (Си) также широко используется для решения вычислительных задач. Достаточно отметить, что сама система Maple 7 создана на языке С.
Для генерации кодов на языке С вначале надо подключить соответствующую функцию:
> with(codegen.C); [С]
Затем можно использовать функцию С:
С(ехрг.folename=str.optimi zed)
Эта функция используется по аналогии с функцией fortran, что и показывают приведенные ниже примеры:
> C(d1ff(x4>,x$2));
t0 = pow(x,1.0*b)*b*b/(x*x)-pow(x,1.0*b)*b/(x*x);
> C(diff(xAb,x$2),optimized);
tl = pow(x,1.0*b);
t2 = b*b;
t4 = x*x;
t5 = l/t4; '
t9 = tl*t2*t5-tl*b*t5;
Обширные возможности преобразования выражений в различные формы предоставляет функция convert. А функция interface позволяет управлять выводом. К сожалению, объем книги не позволяет рассмотреть все многочисленные варианты применения этих функций.
В ряде случаев весьма желательна визуализация результатов выполнения функций пользователя. Порой она может давать неожиданный результат. На рис. 7.1 представлены примеры задания двух функций пользователя от двух переменных и построение их графиков с помощью функции plot3d.
а
б
Рис. 7.1. Примеры задания функций пользователя двух переменных с построением их графиков
ВНИМАНИЕ
При задании функций пользователя рекомендуется просмотреть их графики в нужном — диапазоне изменения аргументов. К сожалению, наглядными являются только графики функций одной и двух переменных.
Другой важный класс функций, которые нередко приходится задавать, — импликативные функции, в которых связь между переменными задана неявно, в виде какого-либо выражения. Самый характерный пример такой функции — это выражение для задания окружности радиуса r: х^2 + у^2 = r^2.
Итак, импликативные функции записываются как уравнения. Соответственно их можно решать с помощью функции solve. Следующие примеры иллюстрируют задание уравнения окружности в общем и в частном (численном) виде:
Для графической визуализации импликативных функций служит функция implicitplot пакета plots. На рис. 7.2 представлено задание двух импликативных функций и построение их графиков.
Рис. 7.2. Задание двух импликативных функций и построение их графиков
В данном случае задано построение двух эллипсов. Верхний — это окружность, сплюснутая по вертикали, а второй — наклонный эллипс.
В объявление процедуры можно включить ключевые слова, вводимые словом
options opseq
Иногда их называют расширяющими ключами. Предусмотрены следующие ключи:
arrow — определят процедуру -оператор в нотации ->; bulltin — определяет функцию как встроенную; call_external — задает обращение к внешним программным модулям; copyright — защищает процедуру от копирования; inline — определяет процедуру как подчиненную (возможно, не для всех процедур - см. справку); load=memberName — загружает нужный для определений процедуры модуль (см. также опцию unload и детали в справке); operator — объявляет процедуру — функциональный оператор; system — определяет процедуру как системную, remember — определяет таблицу памяти для процедуры; trace — задает трассировку процедуры; unl oacNnemberName — выгружает нужный для определения процедуры модуль (см. опцию load).
Ключ remember
Ключ remember обеспечивает занесение результатов обращений к процедуре в таблицу памяти, которая используется при исполнении процедуры. Функция ор позволяет вывести таблицу:
> f:=proc(x) options remember; х^3 end:
> f(2):
8
> f(3):
27
> op(4,eval(f)): table([2 = 8, 3 = 27]) ,
Ключ remember особенно полезен при реализации итерационных процедур. К примеру, в приведенной ниже процедуре (без использования ключа remember) время вычисления n-го числа Фибоначчи растет пропорционально квадрату n:
> f:=proc(n) if n<2 then n else f(n-l)+f(n-2) fi end;
f:=proc(w)if n <2 then и else f(n - l) + ft>-2)endif endproc
> time(f(30)): 27.400
> f(30): 832040
Вычисление f(30) по этой процедуре на ПК с процессором Pentium II 350 МГц занимает около 30 с — см. контроль этого времени с помощью функции time (результат в секундах).
Стоит добавить в процедуру ключ remember, и время вычислений резко уменьшится:
> restart;
> fe:-proc(n) options remember: if n<2 then n else fe(n-l)+fe(n-2) fi end:
Макрос — это макрокоманда, короткая запись длинных определений. По сравнению с переназначениями макросы более гибки и могут использоваться для сокращения операций загрузки новых определений из библиотеки и пакетов. Макросы создаются с помощью функции macro:
macrc(e1, e2, .... en)
где el, е2, ....,, en — ноль или более равенств.
В следующем примере функция numbperm с помощью макроса заменена на пр:
> numbperm([l,2,3,4]);
24
> macro(np=numbperm(V));
nр
> V:=[1.2.3.4]:
F:=[l,2,3,4]
> np(V);
24
Макросы могут быть использованы для конструирования выражений из их макроопределений.
Модули придают языку программирования Maple 7 некоторые свойства языков объектно-ориентированного программирования. Они служат для реализации абстрактного типа данных на основе инкапсуляции — объединения данных и процедур их обработки. Модули задаются ключевым словом module с пустыми скобками () и завершаются словами end module или просто end:
name := module()
export eseq; local Iseq; global gseq:
option optseq: description desc:
Тело модуля
end module (или просто end)
Хотя структура модуля во многом напоминает структуру процедуры, включая объявление локальных и глобальных переменных, параметров и описаний, между ними есть существенная разница:
модуль не имеет списка входных параметров; О в модуле могут размещаться данные; модули могут использоваться для создания пакетов процедур, доступ к которым обеспечивается командой with; модули имеют свойства в виде локальных переменных и методы в виде процедур интерфейса модулей; реализация абстрактных типов данных с помощью модулей скрыта от пользователя; модули могут содержать оператор export eseq, объявляющий экспортируемые переменные модуля; для доступа к экспортируемым переменным модуля может использоваться специальный оператор «:-» (двоеточие и минус); модули и процедуры могут вкладываться друг в друга без ограничения уровня вложенности; модули могут иметь специальные конструкторы объектов.Следующий пример демонстрирует создание модуля pt, в котором заданы две операции (сложения plus и умножения times) и показан доступ к ним:
> pt:= module()
export plus, times;
plus := (a.b) -> a + b;
times := (a.b) -> a * b: end module:
pt := module () export plus, times; end module
> pt:-p1us(3,5);
8
> pt:=times(3,7);
21
Детальную информацию о модулях и о конструкторах объектов можно найти в справках по ним. Некоторые пакеты Maple 7 (в основном сравнительно новые) реализованы уже не в виде процедур, а в виде модулей (например, в виде модуля сделан пакет LinearAlgebra). В простейшем виде модули могут использоваться всеми пользователями системы Maple 7, но их серьезное применение (например, с целью создания полноценных пакетов Maple 7) требует серьезного знакомства с техникой объектно-ориентированного программирования. Такое знакомство выходит за рамки данной книги.
Говорят, что запретный плод сладок! Что бы ни говорили о нежелательности - работы с глобальными переменными, бывает, что их применение желательно или даже необходимо. Чтобы сделать переменные внутри процедуры глобальными, достаточно объявить их с помощью ключевого слова global, после которого перечисляются идентификаторы переменных.
Следующий пример поясняет применение оператора global в процедуре:
> а:=1;b:=1:
а := 1
b := 1
> fg:=proc(x,y)
> global a,b;
> a:-x^2:b:=y^2:
> RETURN(sqrt(a+b));
> end;
fg := proc (x, y) global a, b; a := x^2; b := y^2; RETURN( sqrt( a + b)) end proc
> fg(3.4):
5 > [a.b]:
[9,16]
В примере переменным а и b вначале присвоены значения 1. Поскольку они в процедуре объявлены глобальными, то внутри процедуры они принимают новые значения х2 и у2. В результате при выходе из процедуры они имеют уже новые значения. Это и есть побочный эффект при исполнении данной процедуры. Если пользователь не знает (или не помнит), что та или иная процедура имеет побочный эффект, то он рискует получить самые неожиданные (и неверные) результаты своих вычислений.
ПРИМЕЧАНИЕ
Следует отметить, что нельзя делать глобальными переменные, указанные в списке параметров процедуры, поскольку они уже фактически объявлены локальными. Такая попытка приведет к появлению сообщения об ошибке следующего вида «Error, argument and global'x' have the same name». При этом соответствующие переменные останутся локальными.
Если в теле процедуры имеются операции присваивания для ранее определенных (глобальных) переменных, то изменение их значений в ходе выполнения процедуры создает так называемый побочный эффект. Он способен существенно изменить алгоритм решения сложных задач и, как правило, недопустим. Поэтому Maple-язык программирования имеет встроенные средства для исключения побочных эффектов. Встречая такие операции присваивания, Maple-язык корректирует текст процедуры и вставляет в нее объявление переменных локальными с помощью ключевого слова local и выдает предупреждающую надпись о подобном применении:
> restart:m:=0;
m := 0
> modc:=proc(z)
> m:=evalf(sqrt(Re(zr2+Im(zr2)):RETURN(m)
> end:
Warning, 'm' is implicitly declared local to procedure 'mode'
mode := proc (z) local т; т := evalf(sqrt(9*(z)A2 + 3(z)A2)); RETURN(m) end proc
> modc(3.+I*4.): 5.000000000
> m;
0
Обратите внимание на то, что в тело процедуры было автоматически вставлено определение local m, задающее локальный статус переменной т. Оператором print можно вывести текст процедуры:
> print(modc);
proc(z) local m; m := evalf(sqrt(R(z)^2 + J(z)^2)); RETURN(m) endproc
Выше мы рассмотрели основные частные формы задания процедур. Все они могут быть объединены в общую форму задания процедуры:
name:-proc(<argseq>) # объявление процедуры
local<nseq>; # объявление локальных переменных
g1oba1<nseq>; # объявление глобальных переменных
options<nseq>; # объявление расширяющих ключей
description<stringseq>; # объявление комментарий
<stateq> # выражения - тело процедуры
end; (или end:) # объявление конца процедуры
Эта форма охватывает все описанные выше частные формы и позволяет готовить самые сложные и надежно работающие процедуры.
Как отмечалось, процедуры, которые возвращают значение результата в ответ на обращение к ним, во многом тождественны функциям. Будем называть их процедурами-функциями. Обычно процедура возвращает значение последнего выражения в ее теле или выражения, намеченного к возврату специальным оператором RETURN:
Параметром оператора RETURN может быть любое выражение. В Maple не принято выделять процедуры-функции в какой-то отдельный класс. Действует правило — если не использован оператор RETURN, процедура возвращает значение последнего выражения в ее теле. Для устранения выдачи значений выражений внутри процедуры-функции после них просто надо установить знак двоеточия.
Иногда бывает нужным пропустить определенное значение переменной цикла. Для этого используется оператор next (следующий). Приведенный ниже пример иллюстрирует применение оператора next в составе выражения if-fi для исключения вывода значения i = -2:
> for 1 in [1,2.3.-2.4] do if i--2 then next else print(i) fi od:
1
2 .3
4
Другой оператор — break — прерывает выполнение фрагмента программы (или цикла). Его действие поясняет слегка модифицированный предшествующий пример:
> for i in [1.2.3.-2,4] do if i=2 then break else print(i) fi od:
1
2
3
В данном случае при значении i = -2 произошло полное прекращение выполнения цикла. Поэтому следующее значение 4 переменной z присвоено не было и это значение на печать не попало.
Любой из операторов quit, done или stop обеспечивает также прерывание выполнения текущей программы (в частности, цикла), но при этом окно текущего документа закрывается.
Более гибкий способ задания полноценных функций пользователя базируется на применении функционального оператора. При этом используется следующая конструкция:
name:=(x,y,...)->expr
После этого вызов функции осуществляется в виде name(x.y,...), где (х.у,...) — список формальных параметров функции пользователя с именем name. Переменные, указанные в списке формальных параметров, являются локальными. При подстановке на их место фактических параметров они сохраняют их значения только в теле функции (ехрr). За пределами этой функции переменные с этими . именами оказываются либо неопределенными, либо сохраняют ранее присвоенные им значения. Следующие примеры иллюстрируют сказанное:
Нетрудно заметить, что при вычислении функции m(х.у) переменные х и у имели значения 3 и 4, однако за пределами функции они сохраняют нулевые значения, заданные им перед введением определения функции пользователя. Еще один способ задания функции пользователя базируется на применении функции unapply: name:=unapply(expr.varl.var2,...) Ниже даны примеры такого задания функции пользователя:
Последний пример показывает возможность проведения символьных операций с функцией пользователя.
В большинстве случаев Maple-язык использует достаточно длинные идентификаторы для своих определений, например функций. Однако с помощью функции al i as можно изменить любое определение на другое, если оно кажется пользователю более удобным. Функция alias записывается в виде:
alias(e1. е2. .... еN)
где e1, e2, ..., eN — ноль или более равенств.
Эта функция возвращает список переназначений и осуществляет сами переназначения. Например, для замены имени функции BesselJ на более короткое имя BJ достаточно параметром функции alias записать BJ=BesselJ:
> alias(BJ-BesseU):
BJ,Fx
> [BJ(0.1.),Besse1J(0,1.)]:
[.7651976866, .7651976866]
Можно также переназначить функцию пользователя:
Для отмены переназначения, например BJ, используется та же функция alias с повтором переназначения:
> a1ias(B>BJ): Fx
> BJ(0,1.); BJ(0,1.)
Обратите внимание на то, что BJ исчезло из списка переназначений и функция BJ(0,1.) уже не вычисляется, поскольку ее больше нет.
Процедурой называют модуль программы, имеющий самостоятельное значение и выполняющий одну или несколько операций, обычно достаточно сложных и отличных от операций, выполняемых встроенными операторами и функциями.
Процедуры являются важнейшим элементом структурного программирования и служат средством расширения возможностей системы Maple 7 пользователем. Каждая процедура имеет свое уникальное имя и список параметров (он может быть пустым). Процедуры вызываются так же, как встроенные функции, — указанием их имени со списком фактических параметров. При этом просто процедуры обычно не возвращают каких-либо значений после своего исполнения, хотя могут присваивать значения входящим в них переменным. Процедуры-функции в ответ на обращение к ним возвращают некоторое значение. Они как бы являются новыми функциями, задаваемыми пользователем. Описанные ранее функции пользователя фактически являются процедурами-функциями с несколько упрощенной структурой. Простейшая форма задания процедуры следующая:
name :=ргос(Параметры)
Тело процедуры
end;
Параметры процедуры задаются перечислением имен переменных, например ргос(х) или proc(x.y.z). С помощью знака :: после имени переменной можно определить ее тип, например в объявлении prog(n::Integer) объявляется, что переменная п является целочисленной. При вызове процедуры выражением вида:
name(Фактические_параметры)
фактические параметры подставляются на место формальных. Несоответствие фактических параметров типу заданных переменных ведет к сообщению об ошибке и к отказу от выполнения процедуры.
В качестве примера ниже приведена процедура вычисления модуля комплексного числа г — в данном случае это единственный параметр процедуры:
ПРИМЕЧАНИЕ
После ввода заголовка процедуры под строкой ввода появляется сообщение: «Warning, premature end of input». Оно указывает на то, что ввод листинга процедуры не закончен и должен быть продолжен до тех пор, пока не будет введено завершающее слово end листинга процедуры.
Если после этого слова поставить символ точки с запятой, то листинг процедуры будет выведен на экран дисплея.
Теперь для вычисления модуля достаточно задать обращение к процедуре modc(z), указав вместо z конкретное комплексное число:
> modc(3.+I*4.); 5.000000000
Нетрудно заметить, что при знаке : после завершающего слова end текст процедуры повторяется в строке вывода (в общем случае в несколько ином виде). Если это повторение не нужно, после слова end надо поставить знак двоеточия. Обратите также внимание на то, что для обозначения действительной и мнимой частей процедуры в ее тексте появились готические буквы.
В большинстве случаев составители программ (процедур) редко прибегают к пошаговой их отладке. Средства общей диагностики Maple 7 развиты настолько хорошо, что позволяют выявлять грубые ошибки в процедурах при их выполнении. Иногда, правда, для этого приходится неоднократно «прогонять» процедуру, пока она не начнет работать как задумано. Тем не менее для отладки процедур служит специальный интерактивный отладчик (debugger). Опишем, как его запустить и как с ним работать.
Допустим, мы составили некоторую процедуру demo, вычисляющую сумму квадратов чисел (1^2+2^2+...+n^2):
> demo:=proc(n::integer) local y,i:
> y:=0:
> for i to n do y:=y+i^2 od
> end;
demo := proc (n::integer) local y, i; у := 0;
for i to n do у := у + i^2 end do end proc
> demo(3):
14
Чтобы включить отладчик в работу, надо исполнить команду stopat:
> stopat(demo);
[demo]
> demo(3);
demo:
1* y:=0;
DBG>
Признаком, указывающим на работу отладчика, является изменение приглашения к вводу со знака > на DBG> (как нетрудно догадаться, DB6 означает debugger). Теперь, подавая команды next (следующий), step (шаг) и stop (остановка), можно проследить выполнение процедуры:
DBG> next
0
demo:
2 for i to n do
end do
DB6> step
0
demo:
3 y:=y+i^2
DBG> Step
1
demo:
3 y:=y+i^2
DB6> step
5
demo:
3 y:=y+iA2
DBG> step
14
В последнем случае процедура по шагам дошла до конца вычислений; на этом работа отладчика завершается сама собой.
Можно также вывести листинг процедуры с помощью команды showstat:
> showstat(demo):
demo :=proc(n::integer)
local у, i;
1* y:=0;
2 for i to n do
3 y:=y+i^2
end do end proc
Обратите внимание, что в этом листинге строки вычисляемых элементов пронумерованы. Это сделано для облегчения разбора работы процедуры.
В общем случае отладчик выключается при выполнении команд stopat, stopwhen или stoperr. Если используется команда stopat, то вывод на экран соответствует исполнению последней выполненной команды.
Для отмены этой команды используется команда unstopat.
Команда stopwhen позволяет установить точку наблюдения за указанной в команде переменной. Отменить ее можно командой unstopwhen. Команда stoperror позволяет задать остановку при появлении определенной ошибки. Для отмены этой команды используется команда unstoperror.
Команда cont используется для продолжения работы до следующей точки прерывания, установленной указанными выше командами, или до конца процедуры. Для прерывания отладки можно использовать команду quit. После команды stop можно вычислить любое Maple-выражение.
В действительности команд отладчика намного больше и их функции более развиты, чем это описано выше. Пользователи, заинтересованные в серьезной работе с отладчиком (скорее всего, их немного), могут просмотреть его подробное описание. Для этого в разделе справочной системы Context найдите раздел Programming, а в нем — раздел Debugging.
В уроке 2 рассматривалась работа с файлами документов. Вводимые в текущий документ программные модули хранятся вместе с ним, так что при отказе от загрузки какого-либо документа все его программные блоки не могут использоваться в других документах. Кроме того, порой неудобно загружать объемный документ ради использования одного или нескольких модулей, например процедур. Поэтому в Maple 7 введены средства, позволяющие записывать нужные модули (в том числе результаты вычислений) на диск и считывать их в случае необходимости.
Для записи на диск используется оператор save:
save filename — запись всех определений текущего файла под именем filename; save name_l, name_2, .... name_k, filename — запись избранных модулей с именами name_l, name_2, ..., name_k под именем filename.Считывание имеющегося на диске файла filename осуществляется оператором read:
read <filename>
При считывании все имеющиеся в файле определения становятся доступными для рабочих документов Maple. При записи файлов отдельных определений используется специальный внутренний Maple-формат файлов. Для загрузки файлов типа *.m из стандартной библиотеки используется функция readlib. А для записи файлов в качестве библиотечных достаточно в имени filename оператора save указать расширение .т. Разумеется, можно считывать такие файлы и оператором read, указав в имени файла расширение .m:
> save my_proc,4myJib.nT: # запись файла пу_ргос и
> # библиотечного файла my_lib.m:
> load 'myjlib.m': # считывание библиотечного файла
> # myjib.m.
Если приведенные выше примеры составления процедур кажутся вам простыми, значит, вы неплохо знаете программирование и, скорее всего, уже имеете несколько полезных процедур, которые вы хотели бы сохранить — если не для потомков, то хотя бы для своей повседневной, работы. Сделать это в Maple 7 довольно просто.
Прежде всего надо определить имя своей библиотеки, например mylib, и создать для нее на диске каталог (папку) с заданным именем. Процедуры в Maple 7 ассоциируются с таблицами. Поэтому вначале надо задать таблицу-пустышку под будущие процедуры:
> restart;
> mylib:=tab1e():
mylib := table([])
Теперь надо ввести свои библиотечные процедуры. Они задаются с двойным именем — вначале указывается имя библиотеки, а затем в квадратных скобках имя процедуры. Для примера зададим три простые процедуры с именами fl, f2 и f3:
> mylib[fl]:=proc(x: Anything) sin(x)+cos(x) end:
> mylib[f2]:=proc(x:anything) sin(x)^2+cos(x)^2 end:
> mylib[f3]:=proc(x::anything) if x=0 then 1 else sin(x)/x fi end:
Рекомендуется тщательно проверить работу процедур, прежде чем записывать их на диск. Ограничимся, скажем, такими контрольными примерами:
Можно построить графики введенных процедур-функций. Они представлены на рис. 7,4.
Рис. 7.4. Построение графиков процедур-функций f1, f2 и f3
С помощью функции with можно убедиться, что библиотека mylib действительно содержит только что введенные в нее процедуры. Их список должен появиться при обращении with (mylib):
> with(mylib);
[f1,f2,f3]
Теперь надо записать эту библиотеку под своим именем на диск с помощью команды save:
> save(mylib,`c:/ mylib.m);
Обратите особое внимание на правильное задание полного имени файла. Обычно применяемый для указания пути знак \ в строках Maple-языка используется как знак продолжения строки. Поэтому надо использовать либо двойной знак \\, либо знак /. В нашем примере файл записан в корень диска С. Лучше поместить библиотечный файл в другую папку (например, в библиотеку, уже имеющуюся в составе системы), указан полный путь до нее.
Большая часть функций и операторов системы Maple 7 реализована в виде процедур, написанных на Maple-языке программирования. Благодаря возможности их просмотра пользователь получает неисчерпаемый источник примеров программирования на этом языке. Кроме того, пользователь может создавать свои собственные процедуры.
Для контроля и отладки процедур прежде всего надо уметь вывести их текст. Для этого служит функция:
print(name);
где name — имя процедуры.
Однако перед тем, как использовать эту функцию, надо исполнить команду:
> interfасе(verboseproc=2,prettyprint-l.version);
Maple Worksheet Interface, Maple 7, IBM INTEL NT, May 28 2001 Build ID 96223
Ее смысл будет пояснен ниже. Пока же отметим, что эта команда обеспечивает полный вывод текста процедур библиотеки. Встроенные в ядро процедуры, написанные не на Maple-языке, в полном тексте не представляются. Поясним это следующими примерами:
> print(evalf);
proc() option builtin, remember; 167 end proc
> print(erf);
proc(x::algebraic)
local Re_x, Im_x, sr, si, xr, xi;
option ' Copyright (c) 1994 by the University of Waterloo. All rights reserved`.;
if nargs <> 1 then error "expecting 1 argument, got %1", nargs
elif type(x, 'complex(float)') then evalf('erf (x)) elif x = 0 then 0 elif type(x, 'infinity') then
if type(x, {'cxjnfinity', 'undefined'}) thenundefined + undefined*!
elif type(Re(x), 'infinity') then CopySign(l, Re(x))
elif type(x, 'imaginary') then x
else infinity + infinity*I
end if
elif type(x, 'undefined') then x*undefined elif type(x, 'complex(numeric)')
then
if csgn(x) = -1 then -erf(-x) else 'erf'(x)
end if elif type(x, '*')
and type(op(l, x), 'complex(numeric)')
and csgn(op(l, x)) = -1 then -erf(-x) elif type(x, ' +')
and traperror(sign(x)) = -1 then -erfC-x)
else erf(x) := 'erf'(x) end if end proc
Здесь вначале выполнен вывод сокращенного листинга встроенной в ядро процедуры evalf, а затем выведен полный листинг процедуры вычисления функции ошибок erf.
Эта функция имеет довольно короткую процедуру — многие важные функции и операторы задаются гораздо более сложными и большими процедурами.
Но вернемся к функции interface. Эта функция служит для управления выводом и задается в виде: interface( arg1. arg2, ... ) где аргументы задаются в виде равенств вида name=va1ue и слов-указателей:
ansi |
autoassign |
echo |
error-break |
errorcursor |
imaginaryunit |
indentamount |
labelling |
label width |
latexwidth |
"longdelim |
patchl evel |
plotdevice |
plqtoptions |
plotoutput |
postplot |
preplot |
prettyprint |
prompt |
quiet |
rtablesize |
screenheight |
screenwidth |
showassuraed |
verboseproc |
version |
warnl evel |
Переменные, которые указываются в списке параметров (например, г, в нашем случае), внутри процедуры являются локальными. Это означает, что изменение их значений происходит лишь в теле процедуры, то есть локально. За пределами тела процедуры эти переменные имеют то значение, которое у них было до использования процедуры. Это хорошо поясняет следующий пример:
> restart:z:=l;
z :=
> modc:=proc(z)
> evalf(sqrt(Re(z)"2+Im(z)"2));
> end;
mode := proc(z) evalf(sqrt(<R(z)A2 + 3(z)A2)) endproc > modc(3.+I*4.):
5.000000000
> z;
1
Нетрудно заметить, что внутри процедуры 2 = 3 + I*4, тогда как вне ее значение z= 1, Таким образом, имена переменных в списке параметров процедуры могут совпадать с именами глобальных переменных, используемых за пределами процедуры.
Переменные, которым впервые присваивается значение в процедуре, также относятся к локальным. Кроме того, переменные, применяемые для организации циклов, являются локальными. Все остальные переменные — глобальные.
Хотя ядро Maple 7, библиотека и пакеты содержат свыше 3000 функций, всегда может оказаться, что именно нужной пользователю (и порою довольно простой) функции все же нет. Тогда возникает необходимость в создании собственной функции, именуемой функцией пользователя. Начнем описание с обычных функций пользователя, задающих некоторую зависимость от одной или ряда переменных в явном виде.
Основным средством расширения Maple-языка являются модули — процедуры. Однако на первый взгляд они довольно сложны. Есть и более простые способы задания функций пользователя. Один из таких способов заключается просто в присваивании введенной функции (в виде выражения) некоторой переменной: Name:-выражение
Этот прием фактически означает просто операцию присваивания. Следующие примеры иллюстрируют технику работы с такими функциями:
Заданный таким образом объект все же не является полноценной функцией пользователя, и прежде всего потому, что в нем используются только глобальные переменные (х и у) и нет объявленного списка параметров, от которых зависит значение функции. При этом значения переменных функции приходится заведомо задавать отдельно, используя операции присваивания. Подобные конструкции нельзя ввести в библиотеки Maple 7.
Для подготовки разветвляющихся программ в Maple-язык программирования включен оператор if, позволяющий создавать следующую конструкцию:
if <Условие сравнения? then <Элементы>
|elif «Условие сравнения> then <Элементы>|
|e1se <Элементы>|
fi:
В вертикальных чертах | | указаны необязательные элементы данной конструкции. Следующих два вида условных выражений чаще всего используются на практике:
if <Условие> then <Элементы 1> fi — если Условие выполняется, то исполняются Элементы 1, иначе ничего не выполняется; if <Условие> then <Элененты 1> else <Элененты 2> fi — если Условие выполняется, то исполняются Элементы 1, иначе исполняются Элементы 2.В задании условий используются любые логические конструкции со знаками сравнения (<, <=, >, >=, =, <>) и логические операторы and, or и not, конструкции с которыми возвращают логические значения true и false. Рассмотрим следующий простой пример:
> х:-5:
> if x<0 then print('Negative') fi;
Negative
> x:-l: > if x<0 then print('Negative') fi;
В этом примере анализируется значение х. Если оно отрицательно, то с помощью функции вывода print на экран выводится сообщение «Negative». А вот если х неотрицательно, то не выводится никакого сообщения. В другом примере если х неотрицательно, то выводится сообщение «Positive»:
> х.— 5:
> if x<0 then print('Negative') else print('Positive') fi;
Negative > x:-l:
> if x<0 then printСNegative") else printC'Positive') fi;
Positive
Приведем еще один пример, показывающий особую форму задания конструкции if-then-else-fi:
> х:=-5:
> 'if (x<0, printCNegative').print('Positive'));
Negative
> х:=1:
> *1f (х<0. print("Negative'),printrPositive'));
Positive
В этой конструкции вида 'if '(Условие. Выражение1, Выражение2)
если Условие выполнятся, то будет исполнено Выражение!, в противном случае будет исполнено Выражение2.
Ввиду компактности записи такая форма условного выражения нередко бывает предпочтительна, хотя она и менее наглядна. На рис. 7.3 представлено применение данной конструкции для моделирования трех типов сигналов.
Maple 7 имеет команду system(string), с помощью которой можно исполнить любую команду MS-DOS, записанную в виде строки string. Например, для форматирования гибкого диска из среды Maple 7 можно использовать стандартную команду MS-DOS:
> system(`format a:`);
На экране появится окно MS-DOS с начальным диалогом форматирования диска А. Это окно показано на рис. 7.5.
При работе в операционной системе Windows эта возможность практически бесполезна, поскольку форматирование диска с большими удобствами можно выполнить средствами Windows.
Внешние вызовы командой system куда более полезны для MS-DOS-реализаций Maple, которые кое-где используются и по сей день. Но поскольку данная книга посвящена самым современным Windows-реализациям системы Maple 7, более подробное рассмотрение операций внешних вызовов не имеет особого смысла.
а
б
Рис. 7.5. Результат выполнения команды форматирования гибкого диска
Maple 7 имеет ряд средств для общения с другими программами. Часть из них, в основном относящаяся к обмену через файлы, уже была описана. Однако Maple 7 способна генерировать коды для прямого их включения в такие программы, причем не только математические.
Для подготовки математических статей и книг широкое распространение получили редакторы ТеХ и LaTeX. Для подготовки выражений или файлов в их формате служит функция:
latex(expr.filename)
Параметр filename не обязателен, если достаточно получить нужное выражение в ячейке вывода Maple 7:
> latex(a*x^2+b*x+c):
а{х}^{2}+bх+с
> latex(diff(xAn.x$2));
{\frac {{х}^{n}{n}^{2}}{{х}^{2}}{\frас {{х}^{n}n}{{х}^{2}}}
Maple 7 имеет средства для вызова внешних откомпилированных процедур, написанных на языке С. Такая необходимость для подавляющего числа пользователей Maple 7 вызывает большие сомнения в силу следующих причин:
вся идеология системы Maple 7 основана на максимальном исключении программирования на других языках, помимо Maple-языка; язык С сложен для большинства пользователей Maple 7, которых трудно отнести к «путным» программистам; отладка комплекса Maple 7 + компилятор С (например, фирмы Microsoft) вряд ли под силу обычным пользователям, тем более что на практике такой комплекс реально не работает без кропотливой отладки.Учитывая сказанное, мы отметим лишь, что для использования внешних процедур (например, остро нужных пользователю или более быстрых, чем аналогичные процедуры Maple) используется специальная команды define_external, которая генерирует две интерфейсные программы — на языке С и на языке Maple соответственно. Программа на языке С компилируется вместе с внешней процедурой, которая будет использоваться. Результирующий код создает динамически подключаемую бублиотеку DLL. В свою очередь, программа на языке Maple служит как интерфейсная для организации взаимодействия с вызываемой внешней процедурой. Более подробное описание возможностей работы с внешними процедурами можно найти в справке по ним.
Обширные возможности Maple 7 делают привлекательным применение этой программы для автоматической обработки данных, поступающих от каких-либо экспериментальных установок. Для этого установки снабжаются интерфейсными платами (например, аналого-цифровыми преобразователями) и необходимым программным обеспечением. Возможна и передача данных, полученных с помощью Maple 7, в экспериментальные установки.
Обмен информацией между Maple 7 и внешней средой (к ней, кстати, относятся и другие программы) чаще всего осуществляется через файлы текстового формата, поскольку именно с такими файлами могут работать практически все программы. Для записи данных в файл служит оператор writedata:
writedata[APPEND](fileID. data)
writedata[APPEND](fileID, data, format)
writedata[APPEND](filelD, data, format, default)
Здесь filelD — имя или дескриптор файла данных, data — список, вектор или матрица данных, format — спецификация формата данных (integer, float или string), default — процедура, задающая запись нечисловых данных, например:
writedata(F.A.float.proc(f.x) fprintf(f/CMPLX(%g,%g)',Re(x).Im(x)) end):
Необязательный указатель APPEND используется, если данные должны дописываться в уже созданный файл. Считывание из файла filename обеспечивает функция readdata:
readdata(filelID. n)
readdata(fileID, format, n)
readdata(fileID. format)
Здесь n — целое положительное число, задающее число считываемых столбцов. Ниже представлены примеры этих операций:
Maple 7 имеет также типичные файловые операции:
writeto — запись в файл; appendto — добавление к файлу; open — открытие файла; close — закрытие файла; write — запись в открытый файл; save — запись выражений в файл; read — считывание из файла.Их реализация, однако, зависит от платформы, на которой установлена система, и от ее настройки.