Манзон Б.М. Maple V Power Edition (1185908), страница 17
Текст из файла (страница 17)
Сравним при помощи команды Еще времена, затрачиваемые процедурами для вычисления 20-ого числа Фибоначчи; > сыае(Р(20) ) теыпе(Р1Ьопасс1(20) ) т 0 6.038 8. Программирование в среде Марте Вложенные процедуры Вспомним команду гпар, Как вы уже знаете, эта команда применяет функцию к списку. Если, например, задан список > кевсакс т 1вс: = (2, 4, 5, 6) т Вг:= [2,4, 5,6[ и мы хотим все его элементы возвести в степень, равную первому элементу списка (2), то можно записать процедуру > агар(х->х 1вт.(1),1вс), [4, 16, 25, 36) Как записать эту процедуру внутри другой процедуры, которая будет внешней для процедуры вар (назовем ее оц1)? Попробуем вначале записать так > ч:='ч'тоие.а=рюсс(хгг11вс) 1оса1 чг ч:=х(1) г гвар(у->у ч,х) едет т:= г оиГ:= ргос(х::Ы) !оса! 1; г:= х[Ц; гпар(у — > у" г, х) епа > оис(1вс) ! [2", 4', 5', 6') Такая запись процедуры не привела к нужному результату, так как будучи локальной для процедуры оцг, переменная у не перенесла присвоенное ей значение х[Ц во внутреннюю процедуру у — > у"у.
Теперь попробуем в процедуре оц11 переменную т продекларировать как глобальную > оиц1:=рюсс(хгг11вс) д1оЬа1 тгт ч:=х(1)т аьар(у->у ч,х) атме) ои(1:= ргос(хпЫ) й)ойа! г; т:= х[Ц; гпар(у — > у"т, х) евй > оис1(1вс) т [4, 16, 25, 36[ 162 Мар!е Ч Роччег Ео(т!оп Теперь все в порядке, однако продекларируем ч как локальную в процедуре ов12 и как глобальную во вложенной процедуре > згг='зг'Гои~2г=расс(хгг1з.вС.) 1оса1 хгг хг:=х[1] г шар(рхос(у) д1о]за1 згг у"зг) епй,х) епй) оиГ2:= ргос(хх)(з1) 1оса) ч; ч:= х[1[; гпар(ргос(у) й!оЬа1 ч; у ч епо, х) еле( > оис2(1вс) г [2", 4", 5', 6"[ Такая запись также не приводит к нужному результату. Это можно объяснить тем, что во внутренней процедуре переменная ч является глобальной и позтому отличается от локальной переменной ч процедуры оц12.
Попробуем передать переменную ч во внутреннюю процедуру через параметр внутренней процедуры > оисЗ:=рхос(х:зевс) зпар(рхос(у,в) у"вг епй,х,х[1]) епйг оигЗ:= ргос(ж:1(зг) шар(ргос(у„а) у"~ епо, х, х[1]) епв > оисЗ(1вс) ) [4, 16, 25, 36[ Теперь получился правильный результат. Однако есть и другие приемы. Можно использовать команду ппарр)у вместо оператора глрслки или ргос() для создания вложенной процедуры. > ипарр1у(у"зг,у)г Эта команда создает процедуру из математических выражения с аргументом у. Причем, внутри созданной таким образом процедуры переменные, не являющиеся аргументами процедуры такие же какими они являлись вне процедуры, то есть глобальные для процедуры оцк Запишем еще один вариант вложенной процедуры.
8. ПРограммирование в среде Мар1е ! 6З > оис4г расс(хгг1л.аЬ) ииарр1у(у"х(1],у)! зпар(",х) а; оиг4:= ргос(х::й|) цпарр1у(у х[1[, у); гпар(", х) епй > оис4 (1вп) ) [4, !б, 25, Зб[ Еше один прием — использование команды подстановки апЬа для замены слобальной переменной вложенной процедуры значением локальной переменной процедуры овп > оис5г=расс(х.":11вс) 1оса1 ч; д1оЬа1 зг! ргхис('ато тг',вг)1 чг=х(1]т агар(виЬа( чг =ч,у->у"тг),х) етой г оог5:= ргос(хл(1зг) 1оса! г; 410Ьа! кб рппг('это в', в); г:= х[1); шар(апЬа('в'= г, у — > у"в), х) еп4 > оис5 (1вЬ) т эгло ю, ю [4, 1б, 25, 36) Здесь я берется в кавычки, чтобы исключить ошибки в случаях, когда глобальному имени в присвоено некоторое значение.
Когда в в кавычках, то используется только имя тч. Этот метод передачи значений локальных переменных во вложенную процедуру работает всегда, но программы получаются менее ясными для понимания и более сложными для прочтения. Итак, подведем итоги. Для передачи значения некоторой переменной а в процедуру!от(), вложенную в процедуру оцг() можно применить следующие приемы: е в процедуре оцг() определить переменную а как глобальную; е передать переменную а во вложенную процедуру 1п10 через параметр вложенной процедуры; 1п1(,а); 164 Мар1е Ч Ромег ЕоИ1оп + определить (если это возможно) вложенную процедуру при помощи оператора — функции, созданного командой ппарр!у; я передать значение локальной переменной а процедуры оигО во вложенную процедуру 1п1() при помощи вспомогательной глобальной переменной ч процедуры оп10 и функции подстановки ацЬз(а=а,ин()). Ньютоновская итерация Как известно итерационный метод дает возможность получать последовательные все более точные значения искомой величины по ее предыдущему значению.
Один из наиболее известных итерационных методов — метод касательных Ньютона для нахождения корней алгебраических функций. В качестве примера символьного программирования напишем процедуру 1 )птоп11егаг(оп, даюшую по заданной функции формулу итерации. Формальными параметрами процедуры будут алгебраическое выражение и имя переменной. Результатом процедуры должна быть функция, выражающая формулу, по которой будут вычисляться последовательные значения переменной, > гееСагС.) в1езесоп1гегас1опи= ргос(ехрг:га1деЬга1с, х:: пазве) 1оса1 Ыегас.фопт 1СегаИопг=х-ехрг/Й.Н(ехрг,х); ипарр1у(ЫегаМоп, х) епоа Нецтоп11егаГГоп:= ргос(ехрг.:а!аеЬга(с, х::патпе) )оса) йегаИоп; (гегапоп:= х — ехрт/Й(Г(ехрт, х); ипарр)у(йетаггоп, х) ева Чтобы получить функцию по заданному выражению в процедуре применена команда иварр)у.
В качестве примера возьмем выражение > ехрг:=хее1п(х)-ацгС.(х)т ехрг:= х гйп(х) — Гх График его изображен на рис. 69 > р1ос.(ехрг,х=-1..10)т 8. Программирование в среде мар!е )65 Рис. б9 Применим процедуру > Рохш: еИечсопТсекас1оп (ахи, х); х ап(х) — Й Роге: — х -+ х 1 1 а)п(х) + х соа1х) 2 "Гх Зададим начальное значение переменной > хОю=9.01 хд:= 9.0 и найдем несколько Ньютоновских итераций > ~о 4 ао хО:=Го* [хО);оа; хО;= 9.089137810 хО:= 9.086631757 хО:= 9.086629934 хО;= 9.086629934 166 Мар!е Ч Роигег ЕИШоп Мы видим, что значение хО очень быстро приближается к значению корня функпии. Можно эту же процедуру записать в виде, когда формальным параметром процедуры является также процедура > гев~ахЬ.7Иевг~опХйека~ъоп: =рюсс (й: гржосейихе) (х->х)-Е/)З(й) 1 епйт Хенюпйегайоп:= ргос(г.;ргосеЫиге) (х ~ х) — ЯВ(7) евв > д.«= х-> х*айп(х)-вцжЬ (х) ) я:= х — ~ х в(п(х) — чх > в.охзв2: =Втемсоп1сехасхоп(д) 1 Рогт2: х -+ х 1 1 х -э яп(х) + х соа(х) — —— 2 Чх > х01=9.01 хО:= 9.0 > Ьо 4 йо хО:=Роххв2(хО) ойт хО:= 9.089137810 хО;= 9.086631757 хО:= 9.086629934 хО:= 9.086629934 Оператор аффинного преобразования В качестве еше одного примера, позволяюшего освоить приемы программирования в Лиар(е, напишем процедуру, вычисляюшую по заданной функции Г(х) функцию Г(а*х+Ь), — так называемый оператор аффинного преобразования переменной (назовем его 'ай'-оператор).
> аЫ:вркос(й::рхосейпхе,а:юпцагеххс,Ьююпшвекхс) 1оса1 хт цпарр1у(й(а*х+Ь),х) епйт аЯ':= ргос()зргосег)иге, ахпитегк, Ьзпитепс) 1оса! х; ипарр1у(7(а*х + 6), х) епв 8. Программирование в среде Мер(е (В7 Проверим > вой(в1тх,2,1]т х -+ яп(2 х + 1) Построим график (рис. 70) > р1ос(",О..Р1) т Рис. 70 Мы видим, что процедура работает. Однако возьмем функцию от двух переменных > Ас ы(зе 1г) ->зе*в1тз(У) т А:= (х, у) -+ хяп(у) > айй(А,2,1)у Егхох, (хп айй) айй паев а 4ЬЬ ахрлепе, Ь (ой сура потех(с) ъЫсЬ (а пйааупд Теперь у нас ошибка, поскольку в записи процедуры мы указали только одну переменную для формального параметра. Используем такой прием. Внутри процедуры а1Т введем процедуру преобразования одного из аргументов 168 Мар!е Ч Рочвег Ег(11!оп вспомогательной глобальной функции Г с произвольным числом аргументов.
А затем применим оператор подстановки для замены вспомогательной функции на фактическую. Теперь процедура будет выглядеть так > аййу=ргос(йугргосегхиге,ауупиувет1с,Ьуупиувет1с) д1оЬа1 в, д, Ьу виЬв(('е '=й,д а,Ь=Ь),х->У(д*х+Ь,атдв(2.. — 1])) епйу ауу:= ргос(У::ргосейиге, ахпитепс, Ьхпитепс) й)оЬа! г, я, Ь; ацЬз(('Г' = Х Ь = Ь, я = а), х -э г(ф"х + 6, агяз(2 ..
— 1])) ево Здесь агав(2..— 1! перечисляет все аргументы функции, начиная со второго. > абай (в1п, 2, 1) у х -+ гйп(2 х + 1, агяз,,) > "(х) у гйп(2 х+ 1) Теперь проверим, как работает эта программа для функции от двух переменных > Аау =айй (А,2, 1) у Аа;= х -+ А(2 х + 1, агяз,,) > Аа(х,у) у (2 х+ 1) гйп(у) Теперь процедура работает для функций от нескольких переменных. Обобщим далее оператор сдвига, чтобы он мог преобразовывать любую переменную функции. Вторым параметром процедуры теперь будет номер сдвигаемой переменной, а третьим и четвертым — параметры преобразования. > аййу=ргос(йуургосегхите,пууров1пт.,ауупиувегзс, Ьуупшоет1с) д1оЬа1 е.,вг,д,Ьу виЬв(в'=й,уо=п,д=а,Ь=Ь,ргос() Г(агдв (1..ув-1], диатдв (уа]+Ь, агдв (в+1 ..
-1] ) епс]) епйу ао":= ргос(Я.:рюсейиге, и::розтг, ахпитепс, Ьхпитепс) а]оЬа( Ь; т, я, Ь; 8. Программирование в среде Мар/е 169 авЬа( Т' =У т = и, я = а, Ь = Ь, ргос()Е(агась[1 .. т — 1], к*агу[т] + Ь, агиа[т + 1 .. — 1]) епй) епй Проверим написанную процедуру для функции от двух переменных > Аа2и=айй(А,2,2,1)т Аа2;= ргпсП А(агав[1 .. 1], 2*агав[2] + 1, агав[3 .. — 1]) спи > Ав2(х,у) 1 х яп(2 у+ 1) Построим график (рис. 71) > р1оп ( (А (1, у), Аа2 (1, у) ), у=О .. 10) т 0.5 -0.5 Рис. 71 1ТО Мар!е У Роигег Ег((т(оп 8.1.3.
Методы отладки программ В этом разделе мы ознакомимся с методами отладки процедур Мар(е. Трассировка Наиболее простой метод отладки — применение средства рпв11ече1, позволяющего проследить за выполнением программы. рпв11ече! — глобальная переменная, которая при начальной загрузке Мар!е равна 1. Если присвоить ей большее целое значение, то при выполнении процедуры на экран будут выводиться последовательность присваиваний, вход и выход из процедуры с перечислением значений параметров процедуры (трассировка процедуры). Величина переменной рпв1(ече1 определяет уровень (глубину) вложенных процедур, которые будут трассироваться при выполнении программы.
Для того чтобы читалась процедура с глубиной вложения п нужно задать рг1в11ече1:=и к 5. Применим трассировку для выяснения ошибки в записанной выше процедуре ош. > оисг=рхос(хиг11ас) 1оса1 чг чгг=х(1] г в)ар (у- >у*ъ", х) егм11 аи):= ргос(ххйг)) !оса! ч; ч:= х(1]; шар(у -+ у ч, х) еп(( Зададим для переменной рпв(1ече1 значение, достаточное, чтобы читались процедуры второго уровня вложения. > рг1гг~1ехге14 =101 рпп((ече(:= 10 > оис((2,3,4,5])г (-> епсех опс, ахдя = [2, 3, 4, 5] ч:= 2 (-> епеег ип)<помп, ахдя = 2 — 2"ч) <- ехьс ип)<поьп (пои ]п оис) (-> епеех ип)<поип, агдя = 3 3 ч) <- ехгс пп)<почгп (пою уп опс) (-> епеех ип)<поип, ахдя = 4 З.
Программирование в среде ))4арГе 171 < — ех1т пп)<пояп (пои 1п опт) = 4 у) (-ь ептет ппхпонп, атдя = 5 5" < — ехтс ппкпож (пои (п опт) = 5 у) [2', 3",4', 5',[ <- ех(С опт (пои аС Сор 1еуе1) = (2 у, 3 "у, 4 у, 5 "и) ) [2', 3', 4', 5',[ Из распечатки видно, что во вложенную процедуру не передается значение переменной ч. Если в программе встречается системная ошибка, то при значении рпп([ече[> 3 Мир(е распечатает на экране параметры всех процедур, выполняемых на данный момент, значения локальных переменных и команду, которая выполнялась при возникновении ошибки. Приведем пример с ошибкой '*деление на ноль". > й:= расс(х) 1оса1 уг в:=5) д(х,у) г егИ) Хатп(пд, 'г' (я (шр11сус1у с)ес1атес) 1оса1 (:= ргос(х) !оса! у, ~; ~:= 5; я(х, у) еп() > дг =рюсс (в, с) 1оса1 тг,тгг тт: =0) ъ".
=и/тг) тг+зг) еххйт я:= ргое(г, () )оса! и, у; и:= О; ):= Г/и; и + у евв Присвоим переменной рпвйете! значение 4. > ркххг~1езге1:=4) рт(п((еуе(:= 4 > й(х)г ( †> епсет Й, атдя = х г:= 5 <- ЕККОК 1п Е (пои ас Сор 1еуе1) = 61у(я1оп Ьу гето) Еттот, (1п д) ЙЮ1ятоп Ьу гето ехеспс(пд ясасешепс: у := т!и 1оса1я с(елетпес) ая: и = О, д са11ес) ж(СЛ атдптепСя: х, у Е са11ес) нттЬ атдшпепгя; х 172 Мер!е Ч Роигег Ее)Шоп Для трассировки процедур используются также команды Мер(е (гасе, апггасе, которые„в отличие от вышеописанного метода, позволяют выборочно включать и отключать трассировку некоторых из вложенных процедур, чтобы исключить громоздкий вывол на дисплей.