Математика. Настоящий учебник посвящен системе Mathematica прикладному пакету компьютерной алгебры, при помощи которого можно решать любые задачи, в которых в той или иной форме встречается математика
Скачать 4.43 Mb.
|
m точкой с запятой; Предостережение. Условный оператор If вызывается с двумя аргументами, вместо обычных трех или четырех . Мы можем позволить себе делать это только потому, что эта функция написана нами в чисто учебных целях, и мы собираемся использовать ее для небольших значений n, когда PrimeQ гарантировано дает достоверный ответ True или False. В следующем параграфе мы объясняем, почему во всех серьезных случаях для оператора If мало и трех аргументов. Конструкцию With[ {x=a,y=b},body] можно воспринимать как совмест- ное ослабление конструкций Module[ {x=a,y=b},body] и Block[{x=a,y=b},body]. 206 Однако между ними имеется существенное различие, состоящее в том, что с случае конструкций Module и Block значения a и b рассматриваются как начальные значения переменных x и y в вычислении body. В дальней- шем в процессе вычисления body эти значения могут меняться на каж- дом шаге и в вычислении окончательного ответа участвуют уже какие-то совсем другие значения x и y. В то же время в случае конструкции With переменные x и y становятся внутри нее локальными константами a и b и именно они используются на всех шагах вычислении body. Эта кон- струкция не создает новых переменных, а локализует только их значения: • Все имена переменных используемых конструкцией With являются гло- бальными. Однако присвоенные внутри нее значения этих переменных не влияют на их глобальные значения. Например, x=1; With[ {x=2},y=x^2]; x+y даст Вам 5, а не 6. • Если имена переменных входят в конфликт, то в соответствии с общим принципом last in, first out всегда используется самое глубокое значение переменной. Например, With[{x=a},With[{x=b},f[x]]] даст Вам f[b]. • Конструкция With полупрозрачна: значения тех переменных, имена которых не входят в конфликт, продолжают оставаться видимыми локаль- но. Например, With[ {x=a},With[{y=b},f[x,y]]] даст Вам f[a,b]. В то же время, команда Unique действует прямо противоположным об- разом. Она каждый раз явно порождает уникальную переменную. Эту команду можно использовать следующим образом: • Unique[] создает новый символ с именем формата $ModuleNumber, • Unique[x] создаст новый символ с именем формата x$ModuleNumber, • Unique["x"] создаст новый символ с именем формата xModuleNumber. Следующие два диалога хорошо иллюстрируют, что происходит при при- менении этой команды. In[24]:=Table[Unique[x], {i,1,10}] Out[24]= {x$85,x$86,x$87,x$88,x$89,x$90,x$91,x$92,x$93,x$94} In[25]:=Table[Unique["x"], {i,1,10}] Out[25]= {x71,x72,x73,x74,x75,x76,x77,x78,x79,x80} В этот момент Вы должны всерьез задуматься, действительно ли Вам нуж- но несколько сотен индивидуальных переменных, имена которых начи- наются с x или, все же в этом случае удобнее рассматривать совокупность этих переменных как массив значений функции x или как компоненты спис- ка x. Более того, и с точки зрения компьютера вычисления с функцией или списком значительно эффективнее!!! 207 § 11. Равенство и тождество: == Equal versus === Same Равенство есть продукт непротивления сторон. Математик Сейчас мы объясним еще два значения, на которые символ = расщепля- ется в Computer Science, а именно, равенство == и тождество ===. x==y Equal[x,y] равно x!=y Unequal[x,y] не равно x===y SameQ[x,y] тождественно x=!=y UnsameQ[x,y] нетождественно В первом приближении разницу в использовании этих операторов мож- но объяснить так: сравнивая значения двух выражений, нужно писать lhs==rhs в то же время сравнивая форму этих выражений, следует писать lhs===rhs. В частности, во всех командах , связанных с символьным или числен- ным решением уравнений, уравнение f (x) = g(x) должно записываться как f[x]==g[x]. Запись уравнения в форме f[x]=g[x] представляет собой грубейшую ошибку!!! Эта ошибка настолько очевидна, что даже обсуж- дать ее смешно, ведь запись с помощью Set представляет собой присваива- ние, т.е. попытку изменить текущее значение f (x) на g(x). В большинстве случаев, если f (x) имеет защищенный заголовок или когда f (x) уже яв- ляется сырым объектом, система просто не даст нам записать уравнение в такой форме!! Например, попытка написать a*x^2+b*x+c=0, приведет к сообщению об ошибке: Tag Plus in c+b*x+a*x^2 is Protected. Однако хотя различие между == и === менее очевидно, смешение этих операторов приводит к столь же драматическим последствиям. Вот, на- пример, как Mathematica решает квадратные уравнения. In[26]:=Solve[a*x^2+b*x+c==0,x] Out[26]= nn x-> -b- √ b^2-4*a*c 2*a o , n x-> -b+ √ b^2-4*a*c 2*a oo Однако попытка предложить системе вычислить Solve[a*x^2+b*x+c===0,x] приведет к ответу {}. Понятно, почему? В первый раз мы спросили, при каких x значение ax 2 + bx + c равно 0. А во второй раз — при каких x внутренняя форма выражения a*x^2+b*x+c текстуально совпадает с внутренней формой выражения 0. Да ни при каких!!! Упражнение. Как Вы думаете, почему команда решения уравнения име- ет формат Solve[f[x]==g[x],x]? При чем тут x? Решение. Ну это тоже понятно. Это мы знаем, что x обозначает неиз- вестную, но система об этом не должна догадываться. Ну в самом деле, 208 не предлагать же ей по умолчанию решать все уравнения относительно x!! Предложение вычислить Solve[a*x^2+b*x+c==0,a] приведет к ответу a=(-c-bx)/x^2. Так как решение уравнений встречается довольно часто, еще раз под- черкнем, что предикаты Equal[x,y] и SameQ[x,y] следует тщательней- шим образом различать: • Справедливость равенства x==y представляет собой математический вопрос, функция Equal[x,y] возвращает значение True, если x и y имеют равные значения и значение False, если x и y имеют различные значения. Во многих случаях Mathematica на основе имеющихся у нее данных не в состоянии решить, равны x и y или нет!!! В этом случае она просто оставляет выражение Equal[x,y] неэвалюированным. • В то же время справедливость тождества x===y представляет собой алгоритмический вопрос. Функция SameQ[x,y] возвращает значение True, только если x и y реализованы одинаковым образом — имеют одинако- вую внутреннюю форму — и False во всех остальных случаях. Это значит, что Mathematica всегда может дать ответ на вопрос SameQ[x,y]. • Эти ответы очень часто отличаются — две равные вещи не обя- зательно тождественны — как учили нас на уроках диалектического ма- териализма, одинаковое одинаковому рознь! Чтобы сознательно ис- пользовать эти операторы, полезно постараться понять логику системы. Например, 1==1. принимает значение True — ведь это равные числа — но, конечно, 1===1. принимает значение False — хотя бы потому, что 1. не является целым числом! • Единственный случай, когда тождество x===y не требует текстуаль- ного совпадения внутренних представлений — это равенство приближен- ных вещественных или комплексных чисел. В этом случае система может решить, что два числа тождественны, если их разность меньше, чем точ- ность каждого из них. Еще одной типичной ошибкой, которую мы систематически соверша- ли в начале 1990-х годов, было неосторожное использование == в условных операторах. По наивности мы исходили из того, что оператор If[x==y,u,v] должен возвращать либо u, либо v. Но это совершенно не так, в тех слу- чаях, когда система не может решить, действительно ли x==y, она просто оставляет это выражение неэвалюированным, что часто приводит к бес- конечной рекурсии. После нескольких крайне неприятных эпизодов (в те годы ни в интерфейсе Mathematica ни в Mac OS не было предусмотрено прерывание вычисления и мы были вынуждены физически выключать ком- пьютер, теряя все предшествующие вычисления!!!) мы сделали три важных вывода: • better save than sorry; • в сомнительных случаях условные операторы необходимо задавать в виде If[x==y,u,v,w], явно предписывающим значение условного выраже- 209 ния и в том случае, когда система не в состоянии решить, равны x и y или, все-таки, нет! • Часто система не может решить, равны ли два выражения, по чи- сто формальным причинам. Дело в том, что во многих ситуациях она не производит автоматических упрощений. Это значит, что сравнивая два выражения, всегда полезно применить к ним все возможные 54 упрощения!!! Если Вы хотите проверить, равны ли x и y, Ваши шансы на получение правильного ответа резко возрастут, если вместо x==y Вы напе- чатаете Simplify[x]==Simplify[y], FullSimplify[x]==FullSimplify[y], или что-нибудь соответствующее ситуации: FunctionExpand, LogicalEx- pand, Refine, Reduce и тому подобное. • Другой народный способ состоит в том, чтобы задавать условные опе- раторы с использованием === но тогда, конечно, тем более вначале нужно либо упрощать сравниваемые выражения, If[Simplify[x]===Simplify[y],u,v], либо принудительно приводить их к одинаковой форме посредством Fac- tor, Expand и т.д. Предостережение. Как и в языке C++ выражения ==, !=, ===, =!=, <=, >= и т.д. представляют собой командные слова, а внутри слова пробел не ставится. Выражение, содержащее пробел внутри командного слова счита- ется синтаксически неправильным и приводит к сообщению об ошибке. Предостережение. Mathematica исходит из того, что реляционные опера- торы транзитивны!!! Выражение x!=y!=z оценивается как истинное только если x, y, z попарно различны! В частности, 1!=0!=1, истинное с точки зре- ния математических традиций, будет оценено как False. § 12. Решение алгебраических уравнений Как мы знаем, с точки зрения Mathematica выражение f[x]==g[x] пред- ставляет собой уравнение. В системе имплементировано несколько функ- ций для точного (когда это возможно) и приближенного (во всех остальных случаях) решения уравнений. Вот наиболее употребительные из них. Roots[f==g,x] решить полиномиальное уравнение f (x) = g(x) Solve[f==g,x] решить уравнение f (x) = g(x) относительно x Reduce[f==g,x] упростить уравнение f (x) = g(x) Команды Roots, Solve и Reduce служат для точного решения урав- нений. В то же время команды NRoots, NSolve и FindRoot служат для приближенного вычисления корней. Поясним различие между ними. • Roots[f==g,x] является самой слабой командой, которая умеет ре- шать только полиномиальные уравнения в школьном духе. В случае неал- 54 всевозможные! 210 гебраического уравнения или когда она не может найти корни алгебраи- ческого уравнения в духе школьной математики, она просто оставляет их неэвалюированными: In[27]:=Roots[x^5-x-1==0,x] Out[27]=x==Root[-1-#1+#1^5&,1] || x==Root[-1-#1+#1^5&,2] || x==Root[-1-#1+#1^5&,3] || x==Root[-1-#1+#1^5&,4] || x==Root[-1-#1+#1^5&,5] • По умолчанию Roots решает кубические уравнения и уравнения чет- вертой степени в радикалах, иными словами опции Cubics и Quartics поставлены на True. Для того, чтобы решать уравнения совсем уж в школьном духе, нужно включить в тело функции замены Cubics->False и Quartics->False. Однако так как команда Roots использует только полиномиальные ал- горитмы, в некоторых случаях (например при вычислениях в конечных кольцах, полях алгебраических чисел и т.д.) она оказывается весьма по- лезной. Перечислим некоторые команды, связанные с командой Roots. Roots[f==g,x] корни полиномиального уравнения f (x) = g(x) Root[f,n] n-й корень полиномиального уравнения f = 0 RootReduce[y] попытка свести выражение к одному Root ToRadicals[y] попытка выразить все Root в радикалах ToRules[y] преобразовать формат вывода Roots в формат Solve Смысл этих команд ясен сам по себе. Обратите внимание, что в команде Root нет указания на то, относительно какой переменной следует решать уравнение!! Это значит, что первый аргумент должен вводиться не как мно- гочлен, а в формате чистой функции, скажем, вместо x^2+ax+b следует печатать (#^2-a#+b)&. В качестве универсальной команды, дающей — в тех случаях, когда это возможно в элементарных терминах!! — точные решения алгебраических уравнений или систем уравнений, но пытающаяся решить вообще любые числовые уравнения имеющие конечное число корней в том числе и транс- цендентные, начинающий должен рассматривать Solve[f==g,x]. Кроме чисто полиномиальных алгоритмов решения Solve использует другие ин- струменты, такие как обратные функции (опция InverseFunctions). Од- нако при этом в случае бесконечного количества решений Solve как прави- ло ограничивается одной ветвью обратной функции и указывает какие-то решения, а не все решения. • Команду Solve можно применять для решения системы уравнений относительно нескольких переменных. При этом как уравнения, так и неизвестные, относительно которых эти уравнения решаются, можно за- давать в форме списка: Solve[ {f1==g1,...,fm==gm},{x1,...,xn}]. Урав- нения можно связывать также логическими связками, скажем, f1==g1 && f2==g2. В этом случае ответ тоже будет записан как список замен {{x- >a,y->b },...}. 211 • Команда Solve порождает только общие решения и игнорирует ре- шения, возникающие при специальных значениях параметров. В таких случаях нужно применять команду Reduce. Кроме того, под влиянием команды Solve система приходит в такой восторг, найдя какие-то реше- ния, что перестает искать остальные решения, в таких случаях также нуж- но использовать команду Reduce!! Например, попытавшись вычислить Solve[Cos[x]==2,x], Вы получите следующий эфемерный ответ {{x->-ArcCos[2]},{x->ArcCos[2]}} вместе с сообщением о возможной ошибке Solve: Inverse functions are being used by Solve, so some solutions may not be found и советом use Reduce for complete solution information. • С большим отрывом самой общей и самой мощной командой для ре- шения уравнения f (x) = g(x) является Reduce[f==g,x]. Дело в том, что команда Reduce[expr,x] пытается упростить любое выражение expr от x, содержащее равенства, неравенства, включения, логические связки и кван- торы. В случае, когда это выражения состоит только из уравнений и нера- венств, команда Reduce пытается их решить, но делает это гораздо более изощренным образом, чем просто подстановка x в одну из ветвей обратной функции. Таким образом, в отличие от команды Solve, она может указать не какие-то, а все решения уравнения, даже если этих решений бесконечно много. Вот два типичных примера использования Reduce — напоминаем, что в действительности Reduce умеет значительно больше, в частности, решает неравенства и логические формулы!!! ◦ Вычисление Reduce[Cos[x]==2,x] дает правильный ответ C[1] ∈Integers&&(x==-ArcCos[2]+2*Pi*C[1]||x==ArcCos[2]+2*Pi*C[1]) Обратите внимание, что C 1 здесь — произвольная целочисленная посто- янная. В других контекстах Reduce может порождать несколько таких постоянных, принадлежащих различным доменам. ◦ В следующем вычислении мы пытаемся найти целочисленные решения системы уравнений x = y + 1, x 2 = y 3 + 1: Reduce[x^2==y^3+1&&x==y+1, {x,y},Integers] Она находит три таких решения: x==0&&y==-1 || x==1&&y==0 || x==3&&y==2 Следующие команды являются приближенными вариантами обсуждав- шихся раньше точных команд. NRoots[f==g,x] численное решение полиномиального уравнения NSolve[f==g,x] численное решение уравнения f (x) = g(x) FindRoot[f==g,x,x0] корень уравнения f (x) = g(x) вблизи x 0 212 Мы не будем подробно обсуждать использование этих команд, так как оно ясно само по себе. Команды NRoots и NSolve являются численными ана- логами команд Roots и Solve, осуществляющими приближенное вычисле- ние корней полиномиального уравнения или, соответственно, произвольно- го уравнения, имеющего лишь конечное число корней (в случае, если су- ществует алгоритм для их вычисления). С другой стороны команда Find- Root[f==g,x,x0] ищет корень уравнения f (x) = g(x) начиная итеративную процедуру со значения x 0 Глава 6. ФУНКЦИИ Выше было указано, что функции должны определяться незави- симо от того, кому приписано их выполнение. Из перечисления функций можно было убедиться, что они должны определяться и независимо от того, как, каким способом они выполняются. Это иногда затрудняет определение отдельных случаев, так как разные функции могут выполняться совершенно одинаково. По- видимому, здесь имеется влияние одних форм на другие. Это явление может быть названо ассимиляцией способов исполнения функций. В полном объеме это сложное явление здесь не может быть осве- щено. Оно может быть рассмотрено лишь постольку, поскольку это необходимо для последующих анализов. В.Я.Пропп, Морфология волшебной сказки Все на свете является функцией — с точки зрения компьютерной алгебры все, что делается, и все, что происходит, любое изменение значения или формы выражения, любая модификация состояния системы или спосо- ба ее работы называется функцией. Фактически и в предыдущих главах нам не встречалось ничего, кроме функций. В этой главе мы начинаем си- стематическое изучение этого понятия. Мы детально обсудим основные обозначения и понятия, связанные с функциями, и основные классы функ- ций языка Mathematica и чуть более подробно остановимся на арифмети- ческих операциях, числовых функциях и булевых функциях (предикаты и отношения). Это подготовит нас к тому, чтобы в следующей части под- ступить к самой сути языка Mathematica: определению новых функций и функциям работы со списками/применению функций к спискам. |