Иллюстрированный самоучитель по Maple

         

Бинарные (инфиксные) операторы


Бинарные (инфиксные) операторы используются с двумя операндами, обычно размещаемыми по обе стороны от оператора. В ядро 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


Мы уже неоднократно отмечали, что оператор % обеспечивает подстановку в строку ввода (или в выражение) последнего результата операции, Х% — предпоследнего и %%% — третьего с конца. Есть еще одна иногда полезная возможность проследить за ходом частных вычислений внутри документа — применение команды-функции 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. Он записывается в следующей форме: 

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 способна вычислять производные и интегралы от специальных функций.

Рис. 6.4. Примеры применения специальных функций

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

Рис. 6.5. Примеры работы со специальными математическими функциями

На рис. 6.5 показаны примеры разложения специальных функций в ряды и применения функции convert для их преобразования.

Много информации о поведении специальных функций дает построение их графиков. На рис. 6.6 показано построение семейства графиков функций Бесселя BesselJ разного порядка и гамма-функции. Эти функции относятся к числу наиболее известных. Если читателя интересуют те или иные специальные функции, следует прежде всего построить и изучить их графики.

Подробное описание специальных функций можно найти в справочниках [43-45] и в справочной базе данных 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. С ее помощью можно определять новые операторы.



Циклы for и while


Зачастую необходимо циклическое повторение выполнения выражения заданное число раз или до тех пор, пока выполняется определенное условие. 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

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

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

Этот пример имеет не более чем познавательное значение, поскольку для создания такой матрицы Maple 7 имеет функцию identity, с помощью которой функция array позволяет сразу создать единичную матрицу:

В заключение отметим, что возможна упрощенная частная конструкция цикла типа while:

while expr do statseq od:

Здесь выражения statseq выполняются, пока выполняется логическое условие ехрr. Пример такого цикла: 

> n:=1:

n:=1 . 

> while n<16 do n:»2*n od;

n:=2

n := 4

n := 8

n :=16

В этом примере идет удвоение числа n с начальным значением n = 1 до тех пор, пока значение n меньше 16.



Функция вывода сообщений об ошибках ERROR


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

Для контроля за типом данных обычно используются различные функции оценки и тестирования. При выявлении ими ошибки, как правило, предусматривается вывод соответствующего сообщения. Для этого используется функция 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: 


> fe(30);

832040

> time(fe(30)); 

0.

При этом вычисление fe(30) происходит практически мгновенно, так как все промежуточные результаты в первом случае вычисляются заново, а во втором они берутся из таблицы. Однако это справедливо лишь тогда, когда к процедуре было хотя бы однократное обращение. Обратите внимание на то, что данные процедуры являются рекурсивными — в их теле имеется обращение к самим себе.

Ключ builtin

Ключ builtin придает процедуре статус встроенной. Он должен использоваться всегда первым. С помощью функции eval(name) можно проверить, является ли функция с именем name встроенной:

> eval(type);

proc() option builtin; 268 end proc 

> eval(print);

proc() option builtin; 229 end proc

Числа в теле процедур указывают системные номера функций. Следует отметить, что в новой версии Maple 7 они существенно отличаются от принятых в предшествующих версиях.

Ключ system

Этот ключ придает процедуре статус системной. У таких процедур таблица памяти может быть удалена. У обычных процедур таблица памяти не удаляется и входит в так называемый «мусорный ящик» (garbage collector).

Ключи operator и arrow

Эта пара ключей задает процедуре статус оператора в «стрелочной» нотации (->). Это достаточно пояснить следующими примерами:

Ключ trace

Ключ trace задает вывод отладочной информации:

> о:=ргос(х,у) option trace, arrow; x-sqrt(y) end:  

о := proc (x, y) option trace, arrow, x - sqrt(y) end proc

> o(4,2.);

{--> enter o, args = 4,2.

2.585786438

<-- exit о (now at top level) = 2.585786438}

 2.585786438

Ключ copyright

Этот ключ защищает тело процедуры от просмотра. Это поясняют следующие два примера:

> o:=proc(x,y) x-sqrt(y) end: 

о := proc (x, у) х- sqii(y) end proc

> oo:=proc(x.y) option Copyright; x-sqrt(y) end;

oo := proc(x,y) ... endproc 

> oo(4.2);

2.585786438

Нетрудно заметить, что во втором примере тело процедуры уже не просматривается.Для отмены защиты от просмотра можно использовать оператор interfасе(verboseproc=2).



Макросы


Макрос — это макрокоманда, короткая запись длинных определений. По сравнению с переназначениями макросы более гибки и могут использоваться для сокращения операций загрузки новых определений из библиотеки и пакетов. Макросы создаются с помощью функции macro:

macrc(e1, e2, .... en)

где el, е2, ....,, en — ноль или более равенств.

В следующем примере функция numbperm с помощью макроса заменена на пр:

> numbperm([l,2,3,4]);

24 

 > macro(np=numbperm(V)); 

> 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, после которого перечисляются идентификаторы переменных.

Следующий пример поясняет применение оператора 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». При этом соответствующие переменные останутся локальными.



Объявления переменных локальными с помощью оператора local


Если в теле процедуры имеются операции присваивания для ранее определенных (глобальных) переменных, то изменение их значений в ходе выполнения процедуры создает так называемый побочный эффект. Он способен существенно изменить алгоритм решения сложных задач и, как правило, недопустим. Поэтому 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:

Параметром оператора 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-языка используется как знак продолжения строки. Поэтому надо использовать либо двойной знак \\, либо знак /. В нашем примере файл записан в корень диска С. Лучше поместить библиотечный файл в другую папку (например, в библиотеку, уже имеющуюся в составе системы), указан полный путь до нее.


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

> restart;

С помощью команды with можно убедиться в том, что этих определений уже нет:

> with(mylib):

Error, (in pacman:-pexports) mylib is not a package

После этого командой read надо загрузить библиотечный файл:

 > read('c:/mylib.m');

Имя файла надо указывать по правилам, указанным для команды save. Если все выполнено пунктуально, то команда with должна показать наличие в вашей библиотеке списка процедур fl, f2 и f3:

> with(mylib):

[f1. f2. f3]

И наконец, можно вновь опробовать работу процедур, которые теперь введены из загруженной библиотеки:

> fl(x):

sin(x) + cos(x) > simplify(f2(y});

1 > f3(0):

1 > f3(1.);

.8414709848

Описанный выше способ создания своей библиотеки вполне устроит большинство пользователей. Однако есть более сложный и более «продвинутый» способ ввода своей библиотеки в состав уже имеющейся. Для реализации этого Maple 7 имеет следующие операции записи в библиотеку процедур si, s2, ... и считывания их из файлов filel, file2, ...:

savelib(s1. s2, .... sn, filename)

  readlib(f. file1. file2. ...)

С помощью специального оператора makehelp можно задать стандартное справочное описание новых процедур:

makehelp(n.f.b).

где n — название темы, f — имя текстового файла, содержащего текст справки (файл готовится как документ Maple) и b — имя библиотеки. Системная переменная libname хранит имя директории библиотечных файлов. Для регистрации созданной справки надо исполнить команду вида:

libname:-libname. '/mylib":

С деталями применения этих операторов можно ознакомиться в справочной системе.

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


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

Впрочем, идти на это или нет — дело каждого пользователя. Разумеется, если вы готовы создать серьезную библиотеку своих процедур, то ее надо записать и тщательно хранить. С Maple 7 поставляется множество библиотек полезных процедур, составленных пользователями со всего мира, так что и вы можете пополнить ее своими творениями (см. урок 14).



Средства контроля и отладки процедур


Большая часть функций и операторов системы 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

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

Указание verboseproc=n задает степень детальности вывода листинга процедур. При n=0 текст не выводится, при n=1 выводится текст только заданных пользователем процедур, а при n=2 — всех процедур на Maple-языке. Пример этого был дан выше. Указание prettyprint=0 или 1 управляет выводом стандартных сообщений. Указание plotdevice=string управляет выводом графики, например plotdevice=gif указывает на то, что запись графиков в виде файлов будет происходить в формате .gif.

Одним из основных средств отладки процедур является функция трассировки trace(name). Детальность ее работы задается системной переменной printlevel (уровень вывода). При printlevel :=n (значение n = 1 по умолчанию) выводится результат только непосредственно исполняемой функции или оператора. Для вывода информации о выполнении k-ro уровня вложенности надо использовать значение этой переменной от 5*k до 5*(k+i). Так, при п от 1 до 5 выводятся результаты трассировки первого уровня, при и от 6 до 10 — второго и т. д. Максимальное значение п = 100 обеспечивает трассировку по всем уровням вложенности процедуры name.


Следующий пример показывает осуществление трассировки для функции int(x^n,x):

Действие функции трассировки отменяется командой untrace:

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

> 2/0;

Error, numeric exeption:division by zero

> 2/4;

1/2

> 2/.3;

6.666666667

> lasterror:

"division by zero"

> traperror(3/4);

3/4

> lasterror;

lasterror

> traperror(5/0);

Error, numeric exeption:division by zero

> lasterror:

"numeric exeption:division by zero"

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



Статус переменных в процедурах и циклах


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

> 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 представлено применение данной конструкции для моделирования трех типов сигналов.



а



б



в

Рис. 7.3. Применение конструкции с функцией if для моделирования сигналов

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



Внешние вызовы


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. Результат выполнения команды форматирования гибкого диска



Вывод в формате LaTeX


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 — считывание из файла.

Их реализация, однако, зависит от платформы, на которой установлена система, и от ее настройки.