Упрощенные функции пользователя
Хотя ядро Maple 7, библиотека и пакеты содержат свыше 3000 функций, всегда может оказаться, что именно нужной пользователю (и порою довольно простой) функции все же нет. Тогда возникает необходимость в создании собственной функции, именуемой функцией пользователя. Начнем описание с обычных функций пользователя, задающих некоторую зависимость от одной или ряда переменных в явном виде.
Основным средством расширения Maple-языка являются модули — процедуры. Однако на первый взгляд они довольно сложны. Есть и более простые способы задания функций пользователя. Один из таких способов заключается просто в присваивании введенной функции (в виде выражения) некоторой переменной: Name:-выражение
Этот прием фактически означает просто операцию присваивания. Следующие примеры иллюстрируют технику работы с такими функциями:
Заданный таким образом объект все же не является полноценной функцией пользователя, и прежде всего потому, что в нем используются только глобальные переменные (х и у) и нет объявленного списка параметров, от которых зависит значение функции. При этом значения переменных функции приходится заведомо задавать отдельно, используя операции присваивания. Подобные конструкции нельзя ввести в библиотеки Maple 7.
Более гибкий способ задания полноценных функций пользователя базируется на применении функционального оператора. При этом используется следующая конструкция:
name:=(x,y,...)->expr
После этого вызов функции осуществляется в виде name(x.y,...), где (х.у,...) — список формальных параметров функции пользователя с именем name. Переменные, указанные в списке формальных параметров, являются локальными. При подстановке на их место фактических параметров они сохраняют их значения только в теле функции (ехрr). За пределами этой функции переменные с этими . именами оказываются либо неопределенными, либо сохраняют ранее присвоенные им значения. Следующие примеры иллюстрируют сказанное:
Нетрудно заметить, что при вычислении функции m(х.у) переменные х и у имели значения 3 и 4, однако за пределами функции они сохраняют нулевые значения, заданные им перед введением определения функции пользователя. Еще один способ задания функции пользователя базируется на применении функции unapply: name:=unapply(expr.varl.var2,...) Ниже даны примеры такого задания функции пользователя:
Последний пример показывает возможность проведения символьных операций с функцией пользователя.
В ряде случаев весьма желательна визуализация результатов выполнения функций пользователя. Порой она может давать неожиданный результат. На рис. 7.1 представлены примеры задания двух функций пользователя от двух переменных и построение их графиков с помощью функции plot3d.
а
б
Рис. 7.1. Примеры задания функций пользователя двух переменных с построением их графиков
ВНИМАНИЕ
При задании функций пользователя рекомендуется просмотреть их графики в нужном — диапазоне изменения аргументов. К сожалению, наглядными являются только графики функций одной и двух переменных.
Другой важный класс функций, которые нередко приходится задавать, — импликативные функции, в которых связь между переменными задана неявно, в виде какого-либо выражения. Самый характерный пример такой функции — это выражение для задания окружности радиуса r: х^2 + у^2 = r^2.
Итак, импликативные функции записываются как уравнения. Соответственно их можно решать с помощью функции solve. Следующие примеры иллюстрируют задание уравнения окружности в общем и в частном (численном) виде:
Для графической визуализации импликативных функций служит функция implicitplot пакета plots. На рис. 7.2 представлено задание двух импликативных функций и построение их графиков.
Рис. 7.2. Задание двух импликативных функций и построение их графиков
В данном случае задано построение двух эллипсов. Верхний — это окружность, сплюснутая по вертикали, а второй — наклонный эллипс.
Для подготовки разветвляющихся программ в 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 имеет обобщенную конструкцию цикла, которая задается следующим образом:
| 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
В цикле этого вида управляющая переменная может меняться произвольно. Циклы могут быть вложенными. Это иллюстрирует следующий пример, создающий единичную матрицу на базе заданного массива М:
Этот пример имеет не более чем познавательное значение, поскольку для создания такой матрицы 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.
Иногда бывает нужным пропустить определенное значение переменной цикла. Для этого используется оператор 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 обеспечивает также прерывание выполнения текущей программы (в частности, цикла), но при этом окно текущего документа закрывается.
Процедурой называют модуль программы, имеющий самостоятельное значение и выполняющий одну или несколько операций, обычно достаточно сложных и отличных от операций, выполняемых встроенными операторами и функциями.
Процедуры являются важнейшим элементом структурного программирования и служат средством расширения возможностей системы 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 надо поставить знак двоеточия. Обратите также внимание на то, что для обозначения действительной и мнимой частей процедуры в ее тексте появились готические буквы.
Как отмечалось, процедуры, которые возвращают значение результата в ответ на обращение к ним, во многом тождественны функциям. Будем называть их процедурами-функциями. Обычно процедура возвращает значение последнего выражения в ее теле или выражения, намеченного к возврату специальным оператором RETURN:
Параметром оператора RETURN может быть любое выражение. В Maple не принято выделять процедуры-функции в какой-то отдельный класс. Действует правило — если не использован оператор RETURN, процедура возвращает значение последнего выражения в ее теле. Для устранения выдачи значений выражений внутри процедуры-функции после них просто надо установить знак двоеточия.
Переменные, которые указываются в списке параметров (например, г, в нашем случае), внутри процедуры являются локальными. Это означает, что изменение их значений происходит лишь в теле процедуры, то есть локально. За пределами тела процедуры эти переменные имеют то значение, которое у них было до использования процедуры. Это хорошо поясняет следующий пример:
> 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-язык программирования имеет встроенные средства для исключения побочных эффектов. Встречая такие операции присваивания, 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
Говорят, что запретный плод сладок! Что бы ни говорили о нежелательности - работы с глобальными переменными, бывает, что их применение желательно или даже необходимо. Чтобы сделать переменные внутри процедуры глобальными, достаточно объявить их с помощью ключевого слова 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». При этом соответствующие переменные останутся локальными.
При профессиональной подготовке процедур пользователь должен предусмотреть их поведение при возможных ошибках. Например, если он готовит процедуру или функцию, вычисляющую квадратный корень из действительных чисел, то надо учесть, что такой корень нельзя извлекать из отрицательных чисел (будем, исключительно в учебных целях, считать, что комплексные числа в данном примере недопустимы).
Для контроля за типом данных обычно используются различные функции оценки и тестирования. При выявлении ими ошибки, как правило, предусматривается вывод соответствующего сообщения. Для этого используется функция 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.
В объявление процедуры можно включить ключевые слова, вводимые словом
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).
Выше мы рассмотрели основные частные формы задания процедур. Все они могут быть объединены в общую форму задания процедуры:
name:-proc(<argseq>) # объявление процедуры
local<nseq>; # объявление локальных переменных
g1oba1<nseq>; # объявление глобальных переменных
options<nseq>; # объявление расширяющих ключей
description<stringseq>; # объявление комментарий
<stateq> # выражения - тело процедуры
end; (или end:) # объявление конца процедуры
Эта форма охватывает все описанные выше частные формы и позволяет готовить самые сложные и надежно работающие процедуры.
Большая часть функций и операторов системы 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 редко привлекает описанные средства, поскольку проще отладить вычислительный алгоритм прежде, чем на его основе будет составлена процедура. При правильном построении процедур ошибочные ситуации заведомо предусматриваются и должным образом обрабатываются.