Цель лекции: Познакомиться с особенностями представления численных данных в Mathematica и работы с ними.
Главным отличием Mathematica от других вычислительных систем, таких, как калькуляторы, традиционные языки программирования и иные системы вычислений, является возможность эффективной работы с символьными данными. Однако заслуживает внимания и иная возможность пакета, которая роднит его со всеми программами для математических расчетов — умение эффективно работать с численными данными. В большинстве языков программирования перед началом работы с той или иной функцией, следует сначала задавать тип числовых данных. Mathematica самостоятельно улаживает подобные детали: однако понимание особенностей работы программы с разными типами данных поможет раскрыть все её возможности и сделать вычисления более эффективными. Для знакомства с принципами задания чисел в Mathematica и работы с ними за основу возьмём книгу П. Веллина и др. [14].
Первое, что мы сделаем в этой лекции — вспомним типы чисел, с которыми работает Mathematica.
В лекции 2 настоящего курса мы узнали, что в Mathematica существуют четыре типа чисел: целые, рациональные, вещественные и комплексные. Также мы узнали, что числа являются атомарными выражениями, то есть, они не состоят из выражений более низкого уровня. На рисунке 4.1 даны примеры In[1] и In[2] определения типа числа при помощи функции Head[expr] и представления чисел во внутренней форме при помощи FullForm[expr].
Целые числа являются точными и записываются без точки в десятичной дроби. Рациональные числа задаются отношением целых чисел и также рассматриваются программой как точные. Знание внутреннего представления рационального числа может оказаться крайне необходимым при проведении вычислений. Воспользуемся подходом П. Веллина и др. [14, с. 224], в котором он демонстрирует пользу знания внутреннего представления чисел в Mathematica. Пусть из некоторого набора данных необходимо выбрать только рациональные числа. В этом случае следует прибегнуть к использованию шаблонов (pattern matching) — выражений вида x_ (подробней с использованием шаблонов мы познакомимся в лекции, посвящённой функциональному программированию). Однако если мы зададим для поиска шаблон x_/y_, то требуемого результата не добьемся (пример In[3] на рис. 4.1), а анализ по шаблону, заданному функцией Rational[x_,y_], однозначно позволит провести требуемые действия именно с рациональными числами (пример In[4]).
Все числа, содержащие десятичную точку, называются в Mathematica вещественными. Они рассматриваются программой как приближённые. Например, числа 5 и 5.0, кажущиеся пользователю одинаковыми, в Mathematica имеют совершенно разно представление и разные алгоритмы обработки.
Комплексные числа задаются в виде $$a+I*b$$, где $$I$$ — мнимая единица, квадратный корень из $$-1$$. Числа $$a$$ и $$b$$ могут быть целыми, рациональными или вещественными, и в зависимости от этого комплексное число будет рассматриваться как точное (в первых двух случаях) или как приближённое (в последней случае). Внутренняя форма записи комплексного числа — Complex[a,b]. Действительная и мнимая части комплексного числа $$z$$ выделяются при помощи функций Re[z] и Im[z], соответственно (примеры In[5] и In[6] на рис. 4.1). При помощи функций Conjugate[z] и Abs[z] находят комплексно сопряжённое к z число и абсолютное значение z, соответственно (примеры In[7] и In[8]). При помощи функции Arg[z] задаётся угол наклона радиус-вектора точки z на комплексной плоскости (пример In[9]). На рис. 4.2. геометрически проиллюстрированы все параметры комплексных чисел, определяемые при помощи указанных выше функций. Иллюстрацию, благодаря её наглядности, мы позаимствовали в работе П. Веллина и др. [14, с. 232].
(рис 4.1) Работа с разными типами чисел в Mathematica
(рис 4.2) Геометрическое представление комплексных чисел на фазовой плоскости
Акцентируем внимание на том, что при работе с разными типами чисел различаются не только способы представления результатов вычислений, но и применяемые программой алгоритмы вычислений (см. книгу П. Веллина и др. [14, с. 221]). В примерах на рис. 4.3 мы вычисляем синус от угла $$\pi/4$$. В примере In[1], где мы задали в знаменателе целое число 4, Mathematica ищет среди встроенных правил преобразований соответствие заданного выражения с сочетанием функции Sin и выражения Pi/4. В случае успеха она применяет правило преобразования, и в конечном итоге выдаёт алгебраический (точный) результат (см. Out[1]). В примере In[2], поскольку мы изначально задали вещественное, т. е., заведомо неточное число 4.0, конечное выражение находится численно с той же точностью, что и исходное (Out[2]).
(рис 4.3) Результат применения одной и той же функции к численным данным разных типов
В последнем примере во входных данных для вычисления мы использовали особое выражение Pi. Это выражение относится к известным нам из второй лекции именованным константам и осуществляет обращение к числу $$\pi$$. Оно, равно как и другие именованные константы, имеет "двойственную природу" (П. Веллин и др. [14, с. 226]). С одной стороны, оно рассматривается Mathematica не как число, а как символ, что подтверждается примером Out[1] на рис. 4.4. С другой же стороны, сама Mathematica оперирует им как обычным вещественным числом — примеры In[2] и In[3]. Для того чтобы программа могла использовать константы как числа, они имеют специальный атрибут — NumericQ, означающий их численную природу, несмотря на внешнюю форму — пример In[4].
(рис 4.4) Природа именованных констант в Mathematica
По-умолчанию Mathematica работает с числами в десятичной системе счисления (СС), однако, она позволяет переходить и к другим СС при помощи функции BaseForm[dnum,base], где dnum — число в десятичной СС, base — основание СС (пример In[1] на рис. 4.5). Обратная операция перевода числа bnum из системы с основанием base в десятичную осуществляется при помощи операции base^^bnum (пример In[2]).
В другую СС могут быть переведены не только целые числа, но также и числа остальных типов, при этом дробная часть от целой также отделяется точкой. В примере In[3] мы представляем первые 7 цифр экспоненты в двоичной СС.
Для обозначения цифр в СС с основанием больше, чем 10, используются буквы латинского алфавита. Рисунок 4.5 содержит пример In[4] представления первых 30 чисел в СС с основанием 16.
Mathematica позволяет создавать списки, содержащие в качестве элементов цифры некоторого числа. В десятичной СС это делается при помощи функции IntegerDigit[inum] для целого числа inum и при помощи функции RealDigit[rnum] для вещественного числа rnum. При этом во втором случае в качестве результата генерируется вложенный список, содержащий два элемента: первый элемент представляет собой внутренний список с цифрами числа rnum, а второй указывает, после элемента с каким номером ставится точка, отделяющая дробную часть (примеры In[5] и In[6] на рис. 4.5). Для получения списка цифр десятичного числа в СС с иным основанием base в описанные выше функции следует добавить base в качестве второго аргумента (пример In[7]).
В качестве основания СС может выступать любое целое число от 2 до 36. В примере In[8] на рис. 4.5 мы попытались задать основание СС 37: Mathematica не сумела вычислить выражение и выдала соответствующее сообщение.
Подробней о работе с различными СС см. книгу П. Веллина и др. [14, с. 227–228].
(рис 4.5) Работа с числами в разных системах счисления
При работе в области математической статистики нередко возникает необходимость прибегать к случайным распределениям чисел. В Mathematica имеется встроенная функция Random, которая в различных своих формах позволяет генерировать случайные числа в диапазоне и количестве таком, которые требуются пользователю.
Подробней о случайных числах в Mathematica см. книгу П. Веллина и др. [14, с. 229–231].
Выражение Random[] безо всяких аргументов генерирует действительное случайное число из диапазона от 0 до 1 (пример In[1] на рис. 4.6). Функция Random[Integer] случайным образом возвращает числа 0 или 1 (пример In[2]).
Функция Random может иметь три необязательных аргумента: первый задаёт тип генерируемого числа, второй — диапазон, из которого следует выбрать число. Если первый аргумент имеет значение Real, третий аргумент задаёт число цифр, используемых для представления вещественного числа. При помощи Random можно генерировать числа только трёх типов: целые (Integer), вещественные (Real) и комплексные (Complex).
В примере In[3] на рис. 4.6 мы генерируем целое случайное число из диапазона от 0 до 50.
С выражением Random[type,int] можно работать так же, как и с обычными числами, то есть, совершать с ним математические действия, использовать его в качестве аргументов функций, создавать списки и т.д. Единственное отличие при этом будет состоять в том, что при каждом новом вычислении результат будет отличаться от результата предыдущего вычисления того же самого выражения (ср. примеры In[4] и In[5] на рис. 4.6).
(рис 4.6) Случайные числа в Mathematica
В Mathematica все числа, содержащие разделительную точку, рассматриваются как приближённые. При расчётах пользователь самостоятельно может в явном виде задавать приближение числа, оборвав его запись на каком-то знаке (например, записывая число $$\pi$$ с точностью до третьего знака после запятой, 3.152), либо воспользоваться автоматическим приближением при помощи функции N.
При работе с вещественными числами важными являются функции Precision и Accuracy, возвращающие разрядность и точность этих чисел. Определение этих двух понятий позаимствуем в работе Е. М. Воробьёва [1, с. 65]: "Разрядность есть число десятичных цифр, используемых "Математикой" в представлении вещественных чисел при вычислениях, в то время как точность есть число десятичных цифр, используемых для представления дробной части вещественных чисел".
При вычислениях Mathematica для вещественных чисел задаёт либо машинную (по умолчанию), либо неопределенную (произвольную) разрядность. Чтобы узнать машинную разрядность компьютера, необходимо воспользоваться выражением $MachinePrecision либо вывести численное значение константы MachinePrecision. На разных компьютерах это выражение принимает различные значения, но чаще всего его значение близко к 16. В примере In[1] на рис. 4.7 продемонстрировано, что машинная разрядность на компьютере автора курса составляет 15.9546.
Значения функций Precision и Accuracy для целых и рациональных чисел равны бесконечности, или выражению Infinity, выводимому программой в виде значка $$\infty$$ (Е. М. Воробьёв [1, с. 66]) — пример In[2] на рис. 4.7. Таким образом, результат вычислений, в которых фигурируют только целые и рациональные числа, является точным. Среди функций, приводящих к точному результату при точных аргументах, функции сложения, вычитания, умножения, деления, извлечения квадратного корня, логарифма, тригонометрические функции и др. — см. примеры In[3].
Если при записи числа вводится количество цифр вещественного числа, меньшее, чем машинная точность, то считается, что его разрядность равна $MachinePrecision, если же количество введенных цифр вещественного числа превышает $MachinePrecision, то его разрядность равна количеству введенных цифр (примеры In[4] и In[5] на рис. 4.7, соответственно). Mathematica позволяет самостоятельно задавать точность и разрядность при помощи значков " ' " и " '' ", соответственно (примеры In[6] и In[7]).
(рис 4.7) Разрядность и точность представления вещественных чисел в Mathematica
Автоматически, без особых указаний Mathematica при работе с действительными числами выводит на экран шесть значащих цифр числа (пример In[1] на рис. 4.8). Однако это не значит, что в дальнейших вычислениях будут использоваться только показанные пользователю цифры. В примере In[2] (аналогичном примеру из книги П. Веллина и др. [14, с. 237]) мы вычтем из истинного значения числа $$\pi$$ его приближённое значение, выведенное на экран, и в результате получим отличный от нуля результат: это прекрасно иллюстрирует тот факт, что внутреннее значение числа $$\pi$$ отлично от выведенного на экран.
На основе уже полученных в этой лекции знаний мы, наконец, можем разобраться в том, как работает неоднократно использованная нами в предыдущих лекциях функция N[expr]: сначала она преобразовывает заданное действительное число в число с машинной разрядностью, а затем выводит шесть его значащих цифр. Дальнейшие вычисления с этим числом происходят с машинной разрядностью.
Однако при помощи функции N можно вывести на экран численное значение величины и с самостоятельно заданной разрядностью: для этого следует добавить в функцию N второй аргумент, определяющий число значимых цифр в результате вычисления. В примере In[3] на рис. 4.8 мы задали значение разрядности, равное 20.
Внутреннее представление числа num, заданного с некоторой разрядностью, можно узнать при помощи уже известной нам функции FullForm[num]. Если результат вычислений завершается знаком " ' " (пример Out[4] на рис. 4.8), это означает, что число задано с машинной разрядностью; в противном случае число, указанное после знака " ' " означает его разрядность (пример Out[5]).
(рис 4.8) Представление приближённых чисел в Mathematica
Посмотрим теперь, что происходит с разрядностью и точностью при выполнении вычислений. Для этого воспользуемся подходом П. Веллина и др. [14, с. 236]. В примере In[1] на рис. 4.9 мы присвоили выражению expr значение некоторого числа с разрядностью 30, а в примере In[2] мы, во-первых, убедились в том, что его разрядность имеет значение 30, а также определили точность, с которой оно задано. Поскольку перед разделительной точкой в Out[1] стоят значащие цифры, то неудивительно, что разрядность по величине больше точности. Передвинем разделительную точку в выражении expr вправо на 3 разряда, домножив его на 1000, и определим разрядность и точность полученного выражения — пример In[3]. Как мы видим, разрядность не изменилась вовсе, зато точность уменьшилась на 3: это объясняется тем, что в дробной части стало на 3 значащих цифры меньше, чем раньше. Противоположного результата, то есть, увеличения точности мы добьёмся, передвинув в исходном выражении точку влево — пример In[4].
Чем левее мы будем передвигать десятичную точку, тем больше будет величина точности. В тот момент, когда перед разделительной точкой больше не останется значащих цифр, точность по величине превзойдёт разрядность. Убедимся в этом, передвинув в исходном выражении точку влево на 6 разрядов — пример In[5] на рис. 4.9.
Следует акцентировать внимание на том, что в примерах In[2], In[4] и In[5] на рис. 4.9 мы переносили десятичную точку, деля или умножая исходное выражение на точные (целые) числа. Осуществление подобных математических операций с заданным с машинной разрядностью вещественным числом приведёт к изменению разрядности всего результата на машинную и соответствующему изменению точности. В примере In[6] вместо того, чтобы разделить исходное выражение на точное (целое) число 1000, мы умножили его на приближённое (вещественное) 0.001. Результат Out[6] подтверждает сказанное ранее.
Таким образом, разрядность, определяющая количество значащих цифр, от положения десятичной точки не зависит, в то время как точность изменяется при изменении положения точки и может быть как меньше, так и больше разрядности.
Теперь узнаем, каким образом Mathematica определяет разрядность и точность, и почему эти числа зачастую не являются целыми.
Пусть задано приближенное значение вещественного числа $$x$$ с погрешностью $$d$$. Mathematica считает, что число $$x$$ лежит в интервале $$(x-d/2,x+d/2)$$, длина которого равна погрешности $$d$$. Тогда разрядность числа $$x$$ определяется по формуле $$-log_{10}(d/|x|)$$, а точность — по формуле $$-log_{10}(d)$$. Таким образом, число, заданное с точностью a имеет погрешность $$10^{-a}$$, в то же время погрешность отличного от нуля числа $$x$$ с разрядность $$p$$ имеет погрешность $$|x| 10^{-p}$$. В справедливости данного определения можно убедиться в книге С. Вольфрама [15, Часть 3, Глава 3.1, с. 7].
Если прибавить к числу или вычесть из него величину, меньшую погрешности, в представлении на экране это не будет иметь никакого эффекта — пример In[7] на рис. 4.9.
Подробней разрядности и точности чисел см. книги Е. М. Воробьёва [1, с. 65–67] П. Веллина и др. [14, с. 234–242].
(рис 4.9) Природа точности и разрядности выражений в Mathematica
Встроенные функции Mathematica для выполнения численных расчётов (назовём их для простоты численные функции) разработаны с учётом баланса между точностью и затраченным на вычисления временем: чтобы результаты вычислений имели наибольшую точность при минимальном затрачиваемом на получение результатов времени. Для контроля разрядности и точности вычислений встроенные функции Mathematica имеют ряд опций, с которыми мы познакомимся ниже (П. Веллин и др. [14, с. 254]).
Если применить некоторую численную функцию к произвольному вещественному числу, вычисления будут проведены с машинной разрядностью. В примере In[1] на рис. 4.10 мы присваиваем выражению expr некоторое действительное число, причём величину его разрядности задаём 25. В том же примере мы убеждаемся, что разрядность числа действительно имеет значение 25. В примере In[2] мы при помощи функции NIntegrate[fun[var],{var,a,b}], где fun[var] — интегрируемая функция от переменной var, a и b — пределы интегрирования, проводим численное интегрирование некоторой математической функции expr*Sin[x] от переменной x, изменяющейся в пределах от 0 до Pi. В том же примере мы узнаём, что результат интегрирования был получен с машинной разрядностью. Таким образом, при проведении расчёта с некоторой численной функцией результат вычисления будет получен с машинной разрядностью. Также результат с машинной разрядностью будет получен при выполнении простейших математических операций с несколькими числами, хотя бы одно из которых задано с машинной разрядностью — пример In[3] на рис. 4.10.
Если всё жё требуется получить результат с большей разрядностью, следует использовать при записи численной функции опцию, задаваемую в виде PrecisionGoal->p, где p — значение задаваемой разрядности. В примере In[4] на рис. 4.10 мы осуществим то же действие, что и в примере In[2], но используем опцию задания разрядности вычислений. Однако в Out[4] Mathematica выдала нам сообщение о том, что произвести вычисление с заданной разрядностью невозможно. Если при помощи Options[funchead] мы выведем на экран значений всех опций функции с заголовком funchead (в нашем примере это NIntegrate), то увидим, что другая опция WorkingPrecision имеет значение по умолчанию, которое равно машинной разрядности (пример In[5]). Это значит, что, несмотря на нашу заявку получить результат с заданной разрядностью, алгоритм вычисления будет работать с машинной разрядностью. Чтобы всё-таки получить требуемый результат, нужно также изменить и значение опции WorkingPrecision, присвоив ему значение, равное или чуть большее, чем PrecisionGoal — см. пример In[6].
(рис 4.10) Задание разрядности вычислений
Ещё одна опция численных функций — MaxIterations. Как становится понятно из заголовка, эта функция задаёт максимальное количество повторений, выполняемых заданной итерационной функцией в процессе вычислений. Как и П. Веллин и др. [14, с. 255–256], рассмотрим эту опцию на примере функции FindRoot[expr,{var,var0}], ищущей итерационным методом значение переменной var, обращающей выражение expr в 0; на первой итерации var принимает значение var0. Как мы видим в примере In[1] на рис. 4.11, значение MaxIterations по умолчанию равно 100. Для большинства вычислений этой величины достаточно, но может возникнуть необходимость повысить число повторений.
Сравним примеры In[2] и In[3] на рис. 4.11 нахождения нуля функции $$y^20$$, при этом, в первом случае используем автоматическое значение MaxIterations, а во втором случае значительно повысим его. Мы видим, что во втором случае результат оказывается значительно — на несколько порядков — ближе к искомому точному результату (который, как мы знаем, есть число 0). В Out[2] Mathematica выдала сообщение о том, что при заданном числе повторений (в нашем случае это автоматически заданная величина 100) не удаётся найти удовлетворительное при заданной (машинной) точности значение переменной. Поэтому повысить точность вычислений попробуем также, увеличив значение опции AccuracyGoal (пример In[4]). Эта опция оказывает такое же влияние на точность вычислений, как опция PrecisionGoal — на разрядность, и точно также взаимодействует с опцией WorkingPrecision. В Out[4] получаем значение, ещё более близкое к точному.
(рис 4.11) Повышение точности некоторых вычислений при помощи опции MaxIterations
Последняя опция численных функций, с которой мы познакомимся в данной лекции, — EvaluationMonitor. Она позволяет "наблюдать" за выражением в процессе вычислений. Опишем способы её использования, предложенные П. Веллином и др. [14, с. 255–256].
Скажем, вам потребовалось получить каждое промежуточное значение выражения x, которое функция FindRoot[Cos[x],{x,2}] находит в процессе вычисления. Один из способов — выводить промежуточные значения x при помощи команды Print[x], определив её в опции EvaluationMonitor — см. пример In[1] на рис. 4.12. Однако в этом случае вы сможете только увидеть эти промежуточные значения. Для того чтобы была возможность в дальнейшем оперировать промежуточными значениями, следует прибегнуть к иному способу. Сначала нужно присвоить некоторому выражению пустой список: xtemp={}. Затем, задавая функцию FindRoot, определить для опции EvaluationMonitor следующее выражение: AppendTo[xtemp,x], — которое будет добавлять в список xtemp всё новые и новы значения x, получаемые в процессе вычисления — пример In[2]. Результат вычисления будет содержать одноуровневый список, элементами которого будут промежуточные значения вычисления итерационной функции FindRoot (Out[2]).
Подробней об управлении точностью и разрядностью вычислений см. книгу П. Веллина и др. [14, с. 254–257].
(рис 4.12) Наблюдение за процессом вычислений при помощи опции EvaluationMonitor
Зачастую пользователи работают не с отдельными числами, а с некоторым массивом данных, причём эти массивы могут быть достаточно большими, что создаёт определённые трудности в работе с ними. Mathematica использует два особых типа данных, делающих работу с массивами чисел быстрее и эффективнее, — это разреженные массивы и уплотнённые массивы.
При решении множества задач, в частности, при решении обыкновенных дифференциальных уравнений и уравнений в частных производных, больших систем уравнений, а также задач оптимизации, приходится нередко работать с матрицами высокого порядка, которые при этом содержат большое количество нулевых элементов. Подобные матрицы могут быть преобразованы в разреженные массивы — массивы, в которых не все элементы используются, имеются в наличии или нужны в данный момент; большое количество алгоритмов разработано специально для работы с такими объектами.
Разреженные массивы создаются при помощи функции SparseArray. Заданная в простейшей форме, функция SparseArray[{pos1->val1,pos2->val2,...}] генерирует массив, в котором значение pos1 занимает позицию val1, pos2 — позицию val2, и т.д., то есть, весь массив мы от начала и до конца задаём вручную, самостоятельно вводя данные. При этом размерность массива определяется автоматически: в примере In[1] на рис. 4.13 мы задаём двумерный массив, число строк которого определяется наибольшим значением первого элемента списков pos1,pos2,... (в нашем случае оно равно 3), а число столбцов, соответственно, наибольшим значением второго элемента (5 в нашем примере).
Точно такого же результата можно добиться, задав функцию в виде SparseArray[{pos1,pos2,...}->{val1,val2,...}], при этом значения val1,val2,... также занимают соответствующие позиции pos1,pos2,... — пример In[3] на рис. 4.13. При такой форме задания разреженного массива количество позиций pos должно совпадать с числом присваиваемых значений val.
В редуцированной форме функция SparseArray[{pos1,pos2,...}->val] на каждую позицию pos1,pos2,... помещает значение val.
Как разреженные массивы Mathematica рассматривает только объекты, созданные при помощи функции SparseArray. Массивы, созданные при помощи функций, с которыми мы познакомились в лекции 3, будут рассматриваться как обычные списки. Однако такие списки list можно преобразовать в разреженные массивы, применив к ним функцию SparseArray[list] — пример In[4] на рис. 4.13. Если список list является вложенным, то его внутренние списки должны иметь одинаковое число элементов, т.е., в двумерном случае list должен быть матрицей.
(рис 4.13) Задание разреженных списков
Наиболее широко употребимо задание функции в виде SparseArray[data,{d1,d2,..}], которая генерирует массив объектов размерностью d1xd2x..., причём всем позициям, значения которым не присвоены в аргументе data, присваивается значение 0. Например, в примере In[1] на рис. 4.14 мы задаём массив 4x4, диагональным элементам которого присвоено значение номера строки (или столбца, поскольку они равны), а остальным элементам — 0.
Узнать, по каким правилам присвоены значения элементам массива mass можно при помощи функции ArrayRules[mass]. В нашем примере Out[2] на рис. 4.14 мы видим, что ячейкам с конкретными номерами присвоены конкретные значения, а запись {_,_}->0 означает, что всем ячейкам, для которых никаких иных правил не задано, и присваивается значение 0.
Присваиваемое пустым (неупомянутым в аргументе data) ячейкам значение не обязательно должно быть 0: его можно определять самостоятельно при помощи третьего аргумента val0 функции SparseArray[data,{d1,d2,..},val0] — пример In[3] на рис. 4.14.
Выбирать ячейки, которым будет присваиваться значение, можно и более избирательно, задавая в аргументе data более пространные условия. Так в примере In[4] на рис. 4.14 при помощи неоднократно используемого нами условия заполнили главную диагональ числом 1, диагональ выше неё — при помощи условия ({i_,j_}/;j==i+1)->2 числом 2, а диагональ ниже — числом 3.
(рис 4.14) Задание разреженных списков. Продолжение
Разреженные массивы очень удобно и наглядно представлять графически. Для этого к разреженному массиву следует применить функцию ArrayPlot. В примере In[2] на рис. 4.15 мы графически представили небольшой квадратный массив размерностью 5x5, главная диагональ которого заполнена наибольшим в массиве числом 3, диагонали выше и ниже на одну ячейку заполнены числом 2, выше и ниже на две ячейки — числом 1, все остальные ячейки заполнены числом 0. Заметим, что чем меньше значение числа в ячейке, тем по умолчанию светлее тон, заполняющий её в графическом представлении в Out[2]. Можно также самостоятельно выбирать цвета, которые будут соответствовать заданным числам. Делается это во втором необязательном аргументе при помощи опции ColorRules. В примере In[3] мы обозначили 3 красным цветом, 2 — синим, 1 — зелёным, а 0 оставили по умолчанию белым. Помимо задания цветов вручную можно воспользоваться готовыми цветовыми схемами, с которыми мы познакомимся в лекции, посвящённой работе с графикой. Цветовые схемы задаются опцией ColorFunction. В примере In[4] мы использовали опцию в виде ColorFunction->{"Rainbow"}, задав этим радужную цветовую схему.
(рис 4.15) Наглядное представление разреженных массивов графическими средствами
К настоящему моменту мы познакомились с принципами построения разреженных массивов, научились их задавать, наглядно представлять их на экране, раскрашивая в разные цвета. Но нераскрытым до сих пор остаётся вопрос: для чего же нужно использовать разреженные массивы?
В третьей лекции сего курса мы уже познакомились со средствами задания и обработки набора числовых данных — списками. Зачем же нужно ещё одно средство, да ещё и не самое простое для понимания? Для ответа на этот вопрос воспользуемся красивым примером, который приводит в П. Веллин и др. в книге [14, с. 249–250].
Зададим в In[1] на рис. 4.16 разреженный массив размерностью 100000x100000, состоящий из случайных чисел на главной диагонали, а также на диагоналях на одну и две строчки выше и ниже; остальные ячейки имеют значение 0. В примере In[2] при помощи функции ByteCount определим объём компьютерной памяти, который занимает массив. В нашем случае он оказывается порядка 6 мегабайт. Если мы захотим задать обычный плотный массив такой же размерности известными по лекции 3 способами, где память расходуется на все элементы, включая нулевые, то путём несложных вычислений (пример In[3]) получим, что требуемый для его хранения объём компьютерной памяти окажется порядка 80 Гбайт. При попытке задать массив при помощи известной нам функции Table Mathematica выдаёт сообщение о нехватке памяти и даже останавливает ядро, поэтому для сохранения однозначности идентификации входных и выходных данных приведём этот пример последним — In[5] на рис. 4.16.
В примере In[4] на рис. 4.16 при помощи функции Timing[oper;], возвращающей время в секундах, затраченное на выполнение математической операции oper, определим время, которое на данной машине затрачивает Mathematica на нахождение скалярного квадрата заданного разреженного массива. Оказывается, что на компьютере автора курса на это действие затрачивается даже меньше секунды.
Подробней о разреженных массивах см. книгу П. Веллина и др. [14, с. 247–250].
(рис 4.16) Преимущества использования разреженных массивов
Одним из преимуществ языка программирования Mathematica является гибкость в отношении обработки данных различных типов. Например, когда пользователь выполняет расчёты с числами с плавающей запятой, Mathematica определяет тип чисел, с которыми ведётся работа, а затем определяет, следует ли пользоваться стандартным алгоритмом вычислений с машинной точностью или нужно пользоваться иным алгоритмом для осуществления вычислений с повышенной точностью. Такая самостоятельность Mathematica значительно упрощает работу пользователя, однако, за это приходится платить. Платой является необходимость хранения и использования служебной информации. В случае небольших расчётов объём служебной информации незначителен и может не приниматься во внимание, однако при работе с большими массивами данных, например, включающими десятки тысяч строк и столбцов, объём служебной информации значительно возрастает и может серьёзно тормозить вычисления. К счастью, в Mathematica имеется возможность обойтись без части служебной информации, получить ощутимый прирост скорости и уменьшить занимаемый объём памяти. Достигается это при помощи уплотнённых массивов: уплотнённый массив Mathematica представляет список однотипных (целые, вещественные, комплексные) чисел. Для иллюстрации эффекта использования уплотнённых массивов вновь воспользуемся примерами из работы П. Веллина и др. [14, с. 250–251].
В примере In[1] на рис. 4.17 зададим список случайных вещественных чисел размерностью 1000x1000. Поскольку все числа в списке одного типа (вещественные), то Mathematica автоматически рассматривает этот список как уплотнённый массив. Убедиться, является ли список list уплотнённым массивом, мы можем при помощи функции Developer`PackedArrayQ[list]. В случае если является, функция возвращает True (пример In[2]).
На основе уже имеющегося уплотнённого массива создадим неуплотнённый массив, для чего заменим один из элементов имеющегося массива числом, отличным от вещественного, например, заменим целым числом 10 число в 5 строке, 5 столбце — пример In[3] на рис. 4.17; в In[4] мы убеждаемся в том, что полученный массив не является уплотнённым (функция Developer`PackedArrayQ[list] возвращает False).
Теперь проверим при помощи уже известной нам функции ByteCount объём памяти, который занимает каждый из заданных нами массивов — пример In[5]. Первый массив, который является уплотнённым, занимает объём памяти примерно в два с половиной раза меньше, чем второй, не являющийся уплотнённым (Out[5]).
В примере In[6] на рис. 4.17 мы найдём время, затрачиваемое на нахождение максимального значения в каждом из массивов. На первый массив Mathematica затрачивает меньше миллионной доли секунды, поскольку указывает на выходе 0., во втором же на вычисления затрачивается больше сотой доли секунды.
Таким образом, работа с уплотнёнными массивами оказывается более выгодной и в плане объёма памяти, и в плане скорости вычислений.
Большинство встроенных функций организованы таким образом, что они гораздо эффективней работают с уплотнёнными массивами. Однако если время, затрачиваемое программой на обработку обычного списка, близко ко времени обработки уплотнённого массива, то функция не вынуждает Mathematica создавать уплотнённый массив, а продолжает работать с обычным списком.
Для каждой встроенной функции существует собственный минимальный размер списка, при котором он конвертируется в уплотнённый массив. Например, для функции Table это значение равно 250. Если список, заданный этой функцией, содержит число элементов, меньшее, чем 250, то он обрабатывается как обычный список, в противном случае — как уплотнённый массив (ср. примеры In[7] и In[8] на рис. 4.17). Функция Range генерирует уплотнённые массивы при любых аргументах больше 1 (пример In[9]).
Подробней о работе с уплотнёнными массивами см. книгу П. Веллина и др. [14, с. 250–253].
(рис 4.17) Преимущества работы с уплотнёнными массивами
Сколь бы ни было прекрасно работать только с точными и приближенными с высокой точностью числами, зачастую просто нет необходимости в получении сверхвысокоточных результатов. Любое число Mathematica может преобразовать в менее точное, но адекватное для дальнейших вычислений. Для этих целей в программе содержится целый ряд встроенных функций.
Функция Round[expr] по правилам математики округляет число expr до ближайшего целого. Её расширенный вариант Round[expr,a] округляет expr до ближайшего числа, нацело делящегося на a. При этом ни expr, ни a не обязаны быть целыми: они могут быть и вещественными, и рациональными, и даже комплексными. На рис. 4.18 см. примеры In[1] и In[2] использования функции округления Round.
Округление в обход математических правил позволяют совершить функции Floor и Ceiling. Первая, заданная в виде Floor[expr], возвращает ближайшее целое число, меньшее или равное expr, а Ceiling[expr] — ближайшее целое число, большее или равное expr. Расширенная форма Floor[expr,a] возвращает ближайшее число, нацело делящееся на a и меньшее expr. Соответственно, Ceiling[expr,a] возвращает ближайшее число, нацело делящееся на a и большее expr. In[3] и In[4] рис. 4.18 см. — примеры использования функций Floor и Ceiling.
Частично роль Floor берёт на себя функция IntegerPart. Заданная в единственной своей форме IntegerPart[expr] она возвращает целую часть выражения expr (пример In[5] на рис. 4.18).
Любое вещественное число expr может быть преобразовано в рациональное или целое при помощи функции Rationalize[expr] (пример In[6] на рис. 4.18).
Последней в этой лекции представим любопытную функцию Divisible[a,b], которая проверяет, делится ли нацело число a на число b, и в зависимости от результата возвращает True или False — см. пример In[7] на рис. 4.18. Функция Divisible работает корректно только в случае, если a и b являются целыми или рациональными.
Подробней об округлении чисел см. книгу Е. М. Воробьёва [1, с. 67–68].
(рис 4.18) Округление чисел
Разреженный массив — массив, в котором не все элементы используются, имеются в наличии или нужны в данный момент
Разрядность — количество значащих десятичных цифр, используемых Mathematica в представлении вещественных чисел при вычислениях.
Точность — число значащих десятичных цифр, используемых для представления дробной части вещественных чисел.
Уплотнённый массив в Mathematica — список однотипных (целые, вещественные, комплексные) чисел.
В данной лекции мы подробно познакомились с особенностями представления в Mathematica численных данных разных типов. Мы научились задавать численные данные в разных системах счисления, преобразовывать числа из одной СС в другую. Мы научились задавать и использовать случайные числа. Мы познакомились с понятиями разрядности и точности числа, узнали, каким образом Mathematica работает с приближёнными числами, научились узнавать точность и разрядность результатов вычислений и при необходимости самостоятельно задавать их. Мы научились оптимизировать ресурсоёмкие расчёты при помощи использования разреженных и уплотнённых массивов. Также мы познакомились с функциями округления приближённых чисел.
$$5^{1/2}-i$$
$$2.3+4.0i$$
$$7/6-4/i$$
Abs и Arg, найдите их абсолютные значения и углы наклона заданных ими радиус-векторов. При помощи Abs и Arg проверьте результаты, определите, к какому типу численных данных они принадлежат.Conjugate, запишите числа, комплексно сопряжённые заданным.+7, 0 и -7;+7 и -7;а, b и c;expr, заданное как expr=N[e^Pi,30], чтобы
8x8, на главной диагонали которого поместите цифры даты вашего рождения, на диагональ выше главной — число 99, на диагональ ниже главной — число 55, в остальные ячейки — число 77;Round, Floor, Ceiling, IntegerPart и Rationalize, получите число 9. Осуществите обратную операцию, получив 6.2 из 9. Выполните то же задание для любой пары чисел из следующего ряда: 1.1, 2.56, 3, 3.9, 9/5, 4.75, 5.25, 6., 6.3, 7.23, 8.4, 8.5, 9.9.Цель лекции: Познакомиться с особенностями представления численных данных в Mathematica и работы с ними.
Главным отличием Mathematica от других вычислительных систем, таких, как калькуляторы, традиционные языки программирования и иные системы вычислений, является возможность эффективной работы с символьными данными. Однако заслуживает внимания и иная возможность пакета, которая роднит его со всеми программами для математических расчетов — умение эффективно работать с численными данными. В большинстве языков программирования перед началом работы с той или иной функцией, следует сначала задавать тип числовых данных. Mathematica самостоятельно улаживает подобные детали: однако понимание особенностей работы программы с разными типами данных поможет раскрыть все её возможности и сделать вычисления более эффективными. Для знакомства с принципами задания чисел в Mathematica и работы с ними за основу возьмём книгу П. Веллина и др. [14].
Первое, что мы сделаем в этой лекции — вспомним типы чисел, с которыми работает Mathematica.
В лекции 2 настоящего курса мы узнали, что в Mathematica существуют четыре типа чисел: целые, рациональные, вещественные и комплексные. Также мы узнали, что числа являются атомарными выражениями, то есть, они не состоят из выражений более низкого уровня. На рисунке 4.1 даны примеры In[1] и In[2] определения типа числа при помощи функции Head[expr] и представления чисел во внутренней форме при помощи FullForm[expr].
Целые числа являются точными и записываются без точки в десятичной дроби. Рациональные числа задаются отношением целых чисел и также рассматриваются программой как точные. Знание внутреннего представления рационального числа может оказаться крайне необходимым при проведении вычислений. Воспользуемся подходом П. Веллина и др. [14, с. 224], в котором он демонстрирует пользу знания внутреннего представления чисел в Mathematica. Пусть из некоторого набора данных необходимо выбрать только рациональные числа. В этом случае следует прибегнуть к использованию шаблонов (pattern matching) — выражений вида x_ (подробней с использованием шаблонов мы познакомимся в лекции, посвящённой функциональному программированию). Однако если мы зададим для поиска шаблон x_/y_, то требуемого результата не добьемся (пример In[3] на рис. 4.1), а анализ по шаблону, заданному функцией Rational[x_,y_], однозначно позволит провести требуемые действия именно с рациональными числами (пример In[4]).
Все числа, содержащие десятичную точку, называются в Mathematica вещественными. Они рассматриваются программой как приближённые. Например, числа 5 и 5.0, кажущиеся пользователю одинаковыми, в Mathematica имеют совершенно разно представление и разные алгоритмы обработки.
Комплексные числа задаются в виде $$a+I*b$$, где $$I$$ — мнимая единица, квадратный корень из $$-1$$. Числа $$a$$ и $$b$$ могут быть целыми, рациональными или вещественными, и в зависимости от этого комплексное число будет рассматриваться как точное (в первых двух случаях) или как приближённое (в последней случае). Внутренняя форма записи комплексного числа — Complex[a,b]. Действительная и мнимая части комплексного числа $$z$$ выделяются при помощи функций Re[z] и Im[z], соответственно (примеры In[5] и In[6] на рис. 4.1). При помощи функций Conjugate[z] и Abs[z] находят комплексно сопряжённое к z число и абсолютное значение z, соответственно (примеры In[7] и In[8]). При помощи функции Arg[z] задаётся угол наклона радиус-вектора точки z на комплексной плоскости (пример In[9]). На рис. 4.2. геометрически проиллюстрированы все параметры комплексных чисел, определяемые при помощи указанных выше функций. Иллюстрацию, благодаря её наглядности, мы позаимствовали в работе П. Веллина и др. [14, с. 232].
(рис 4.1) Работа с разными типами чисел в Mathematica
(рис 4.2) Геометрическое представление комплексных чисел на фазовой плоскости
Акцентируем внимание на том, что при работе с разными типами чисел различаются не только способы представления результатов вычислений, но и применяемые программой алгоритмы вычислений (см. книгу П. Веллина и др. [14, с. 221]). В примерах на рис. 4.3 мы вычисляем синус от угла $$\pi/4$$. В примере In[1], где мы задали в знаменателе целое число 4, Mathematica ищет среди встроенных правил преобразований соответствие заданного выражения с сочетанием функции Sin и выражения Pi/4. В случае успеха она применяет правило преобразования, и в конечном итоге выдаёт алгебраический (точный) результат (см. Out[1]). В примере In[2], поскольку мы изначально задали вещественное, т. е., заведомо неточное число 4.0, конечное выражение находится численно с той же точностью, что и исходное (Out[2]).
(рис 4.3) Результат применения одной и той же функции к численным данным разных типов
В последнем примере во входных данных для вычисления мы использовали особое выражение Pi. Это выражение относится к известным нам из второй лекции именованным константам и осуществляет обращение к числу $$\pi$$. Оно, равно как и другие именованные константы, имеет "двойственную природу" (П. Веллин и др. [14, с. 226]). С одной стороны, оно рассматривается Mathematica не как число, а как символ, что подтверждается примером Out[1] на рис. 4.4. С другой же стороны, сама Mathematica оперирует им как обычным вещественным числом — примеры In[2] и In[3]. Для того чтобы программа могла использовать константы как числа, они имеют специальный атрибут — NumericQ, означающий их численную природу, несмотря на внешнюю форму — пример In[4].
(рис 4.4) Природа именованных констант в Mathematica
По-умолчанию Mathematica работает с числами в десятичной системе счисления (СС), однако, она позволяет переходить и к другим СС при помощи функции BaseForm[dnum,base], где dnum — число в десятичной СС, base — основание СС (пример In[1] на рис. 4.5). Обратная операция перевода числа bnum из системы с основанием base в десятичную осуществляется при помощи операции base^^bnum (пример In[2]).
В другую СС могут быть переведены не только целые числа, но также и числа остальных типов, при этом дробная часть от целой также отделяется точкой. В примере In[3] мы представляем первые 7 цифр экспоненты в двоичной СС.
Для обозначения цифр в СС с основанием больше, чем 10, используются буквы латинского алфавита. Рисунок 4.5 содержит пример In[4] представления первых 30 чисел в СС с основанием 16.
Mathematica позволяет создавать списки, содержащие в качестве элементов цифры некоторого числа. В десятичной СС это делается при помощи функции IntegerDigit[inum] для целого числа inum и при помощи функции RealDigit[rnum] для вещественного числа rnum. При этом во втором случае в качестве результата генерируется вложенный список, содержащий два элемента: первый элемент представляет собой внутренний список с цифрами числа rnum, а второй указывает, после элемента с каким номером ставится точка, отделяющая дробную часть (примеры In[5] и In[6] на рис. 4.5). Для получения списка цифр десятичного числа в СС с иным основанием base в описанные выше функции следует добавить base в качестве второго аргумента (пример In[7]).
В качестве основания СС может выступать любое целое число от 2 до 36. В примере In[8] на рис. 4.5 мы попытались задать основание СС 37: Mathematica не сумела вычислить выражение и выдала соответствующее сообщение.
Подробней о работе с различными СС см. книгу П. Веллина и др. [14, с. 227–228].
(рис 4.5) Работа с числами в разных системах счисления
При работе в области математической статистики нередко возникает необходимость прибегать к случайным распределениям чисел. В Mathematica имеется встроенная функция Random, которая в различных своих формах позволяет генерировать случайные числа в диапазоне и количестве таком, которые требуются пользователю.
Подробней о случайных числах в Mathematica см. книгу П. Веллина и др. [14, с. 229–231].
Выражение Random[] безо всяких аргументов генерирует действительное случайное число из диапазона от 0 до 1 (пример In[1] на рис. 4.6). Функция Random[Integer] случайным образом возвращает числа 0 или 1 (пример In[2]).
Функция Random может иметь три необязательных аргумента: первый задаёт тип генерируемого числа, второй — диапазон, из которого следует выбрать число. Если первый аргумент имеет значение Real, третий аргумент задаёт число цифр, используемых для представления вещественного числа. При помощи Random можно генерировать числа только трёх типов: целые (Integer), вещественные (Real) и комплексные (Complex).
В примере In[3] на рис. 4.6 мы генерируем целое случайное число из диапазона от 0 до 50.
С выражением Random[type,int] можно работать так же, как и с обычными числами, то есть, совершать с ним математические действия, использовать его в качестве аргументов функций, создавать списки и т.д. Единственное отличие при этом будет состоять в том, что при каждом новом вычислении результат будет отличаться от результата предыдущего вычисления того же самого выражения (ср. примеры In[4] и In[5] на рис. 4.6).
(рис 4.6) Случайные числа в Mathematica
В Mathematica все числа, содержащие разделительную точку, рассматриваются как приближённые. При расчётах пользователь самостоятельно может в явном виде задавать приближение числа, оборвав его запись на каком-то знаке (например, записывая число $$\pi$$ с точностью до третьего знака после запятой, 3.152), либо воспользоваться автоматическим приближением при помощи функции N.
При работе с вещественными числами важными являются функции Precision и Accuracy, возвращающие разрядность и точность этих чисел. Определение этих двух понятий позаимствуем в работе Е. М. Воробьёва [1, с. 65]: "Разрядность есть число десятичных цифр, используемых "Математикой" в представлении вещественных чисел при вычислениях, в то время как точность есть число десятичных цифр, используемых для представления дробной части вещественных чисел".
При вычислениях Mathematica для вещественных чисел задаёт либо машинную (по умолчанию), либо неопределенную (произвольную) разрядность. Чтобы узнать машинную разрядность компьютера, необходимо воспользоваться выражением $MachinePrecision либо вывести численное значение константы MachinePrecision. На разных компьютерах это выражение принимает различные значения, но чаще всего его значение близко к 16. В примере In[1] на рис. 4.7 продемонстрировано, что машинная разрядность на компьютере автора курса составляет 15.9546.
Значения функций Precision и Accuracy для целых и рациональных чисел равны бесконечности, или выражению Infinity, выводимому программой в виде значка $$\infty$$ (Е. М. Воробьёв [1, с. 66]) — пример In[2] на рис. 4.7. Таким образом, результат вычислений, в которых фигурируют только целые и рациональные числа, является точным. Среди функций, приводящих к точному результату при точных аргументах, функции сложения, вычитания, умножения, деления, извлечения квадратного корня, логарифма, тригонометрические функции и др. — см. примеры In[3].
Если при записи числа вводится количество цифр вещественного числа, меньшее, чем машинная точность, то считается, что его разрядность равна $MachinePrecision, если же количество введенных цифр вещественного числа превышает $MachinePrecision, то его разрядность равна количеству введенных цифр (примеры In[4] и In[5] на рис. 4.7, соответственно). Mathematica позволяет самостоятельно задавать точность и разрядность при помощи значков " ' " и " '' ", соответственно (примеры In[6] и In[7]).
(рис 4.7) Разрядность и точность представления вещественных чисел в Mathematica
Автоматически, без особых указаний Mathematica при работе с действительными числами выводит на экран шесть значащих цифр числа (пример In[1] на рис. 4.8). Однако это не значит, что в дальнейших вычислениях будут использоваться только показанные пользователю цифры. В примере In[2] (аналогичном примеру из книги П. Веллина и др. [14, с. 237]) мы вычтем из истинного значения числа $$\pi$$ его приближённое значение, выведенное на экран, и в результате получим отличный от нуля результат: это прекрасно иллюстрирует тот факт, что внутреннее значение числа $$\pi$$ отлично от выведенного на экран.
На основе уже полученных в этой лекции знаний мы, наконец, можем разобраться в том, как работает неоднократно использованная нами в предыдущих лекциях функция N[expr]: сначала она преобразовывает заданное действительное число в число с машинной разрядностью, а затем выводит шесть его значащих цифр. Дальнейшие вычисления с этим числом происходят с машинной разрядностью.
Однако при помощи функции N можно вывести на экран численное значение величины и с самостоятельно заданной разрядностью: для этого следует добавить в функцию N второй аргумент, определяющий число значимых цифр в результате вычисления. В примере In[3] на рис. 4.8 мы задали значение разрядности, равное 20.
Внутреннее представление числа num, заданного с некоторой разрядностью, можно узнать при помощи уже известной нам функции FullForm[num]. Если результат вычислений завершается знаком " ' " (пример Out[4] на рис. 4.8), это означает, что число задано с машинной разрядностью; в противном случае число, указанное после знака " ' " означает его разрядность (пример Out[5]).
(рис 4.8) Представление приближённых чисел в Mathematica
Посмотрим теперь, что происходит с разрядностью и точностью при выполнении вычислений. Для этого воспользуемся подходом П. Веллина и др. [14, с. 236]. В примере In[1] на рис. 4.9 мы присвоили выражению expr значение некоторого числа с разрядностью 30, а в примере In[2] мы, во-первых, убедились в том, что его разрядность имеет значение 30, а также определили точность, с которой оно задано. Поскольку перед разделительной точкой в Out[1] стоят значащие цифры, то неудивительно, что разрядность по величине больше точности. Передвинем разделительную точку в выражении expr вправо на 3 разряда, домножив его на 1000, и определим разрядность и точность полученного выражения — пример In[3]. Как мы видим, разрядность не изменилась вовсе, зато точность уменьшилась на 3: это объясняется тем, что в дробной части стало на 3 значащих цифры меньше, чем раньше. Противоположного результата, то есть, увеличения точности мы добьёмся, передвинув в исходном выражении точку влево — пример In[4].
Чем левее мы будем передвигать десятичную точку, тем больше будет величина точности. В тот момент, когда перед разделительной точкой больше не останется значащих цифр, точность по величине превзойдёт разрядность. Убедимся в этом, передвинув в исходном выражении точку влево на 6 разрядов — пример In[5] на рис. 4.9.
Следует акцентировать внимание на том, что в примерах In[2], In[4] и In[5] на рис. 4.9 мы переносили десятичную точку, деля или умножая исходное выражение на точные (целые) числа. Осуществление подобных математических операций с заданным с машинной разрядностью вещественным числом приведёт к изменению разрядности всего результата на машинную и соответствующему изменению точности. В примере In[6] вместо того, чтобы разделить исходное выражение на точное (целое) число 1000, мы умножили его на приближённое (вещественное) 0.001. Результат Out[6] подтверждает сказанное ранее.
Таким образом, разрядность, определяющая количество значащих цифр, от положения десятичной точки не зависит, в то время как точность изменяется при изменении положения точки и может быть как меньше, так и больше разрядности.
Теперь узнаем, каким образом Mathematica определяет разрядность и точность, и почему эти числа зачастую не являются целыми.
Пусть задано приближенное значение вещественного числа $$x$$ с погрешностью $$d$$. Mathematica считает, что число $$x$$ лежит в интервале $$(x-d/2,x+d/2)$$, длина которого равна погрешности $$d$$. Тогда разрядность числа $$x$$ определяется по формуле $$-log_{10}(d/|x|)$$, а точность — по формуле $$-log_{10}(d)$$. Таким образом, число, заданное с точностью a имеет погрешность $$10^{-a}$$, в то же время погрешность отличного от нуля числа $$x$$ с разрядность $$p$$ имеет погрешность $$|x| 10^{-p}$$. В справедливости данного определения можно убедиться в книге С. Вольфрама [15, Часть 3, Глава 3.1, с. 7].
Если прибавить к числу или вычесть из него величину, меньшую погрешности, в представлении на экране это не будет иметь никакого эффекта — пример In[7] на рис. 4.9.
Подробней разрядности и точности чисел см. книги Е. М. Воробьёва [1, с. 65–67] П. Веллина и др. [14, с. 234–242].
(рис 4.9) Природа точности и разрядности выражений в Mathematica
Встроенные функции Mathematica для выполнения численных расчётов (назовём их для простоты численные функции) разработаны с учётом баланса между точностью и затраченным на вычисления временем: чтобы результаты вычислений имели наибольшую точность при минимальном затрачиваемом на получение результатов времени. Для контроля разрядности и точности вычислений встроенные функции Mathematica имеют ряд опций, с которыми мы познакомимся ниже (П. Веллин и др. [14, с. 254]).
Если применить некоторую численную функцию к произвольному вещественному числу, вычисления будут проведены с машинной разрядностью. В примере In[1] на рис. 4.10 мы присваиваем выражению expr некоторое действительное число, причём величину его разрядности задаём 25. В том же примере мы убеждаемся, что разрядность числа действительно имеет значение 25. В примере In[2] мы при помощи функции NIntegrate[fun[var],{var,a,b}], где fun[var] — интегрируемая функция от переменной var, a и b — пределы интегрирования, проводим численное интегрирование некоторой математической функции expr*Sin[x] от переменной x, изменяющейся в пределах от 0 до Pi. В том же примере мы узнаём, что результат интегрирования был получен с машинной разрядностью. Таким образом, при проведении расчёта с некоторой численной функцией результат вычисления будет получен с машинной разрядностью. Также результат с машинной разрядностью будет получен при выполнении простейших математических операций с несколькими числами, хотя бы одно из которых задано с машинной разрядностью — пример In[3] на рис. 4.10.
Если всё жё требуется получить результат с большей разрядностью, следует использовать при записи численной функции опцию, задаваемую в виде PrecisionGoal->p, где p — значение задаваемой разрядности. В примере In[4] на рис. 4.10 мы осуществим то же действие, что и в примере In[2], но используем опцию задания разрядности вычислений. Однако в Out[4] Mathematica выдала нам сообщение о том, что произвести вычисление с заданной разрядностью невозможно. Если при помощи Options[funchead] мы выведем на экран значений всех опций функции с заголовком funchead (в нашем примере это NIntegrate), то увидим, что другая опция WorkingPrecision имеет значение по умолчанию, которое равно машинной разрядности (пример In[5]). Это значит, что, несмотря на нашу заявку получить результат с заданной разрядностью, алгоритм вычисления будет работать с машинной разрядностью. Чтобы всё-таки получить требуемый результат, нужно также изменить и значение опции WorkingPrecision, присвоив ему значение, равное или чуть большее, чем PrecisionGoal — см. пример In[6].
(рис 4.10) Задание разрядности вычислений
Ещё одна опция численных функций — MaxIterations. Как становится понятно из заголовка, эта функция задаёт максимальное количество повторений, выполняемых заданной итерационной функцией в процессе вычислений. Как и П. Веллин и др. [14, с. 255–256], рассмотрим эту опцию на примере функции FindRoot[expr,{var,var0}], ищущей итерационным методом значение переменной var, обращающей выражение expr в 0; на первой итерации var принимает значение var0. Как мы видим в примере In[1] на рис. 4.11, значение MaxIterations по умолчанию равно 100. Для большинства вычислений этой величины достаточно, но может возникнуть необходимость повысить число повторений.
Сравним примеры In[2] и In[3] на рис. 4.11 нахождения нуля функции $$y^20$$, при этом, в первом случае используем автоматическое значение MaxIterations, а во втором случае значительно повысим его. Мы видим, что во втором случае результат оказывается значительно — на несколько порядков — ближе к искомому точному результату (который, как мы знаем, есть число 0). В Out[2] Mathematica выдала сообщение о том, что при заданном числе повторений (в нашем случае это автоматически заданная величина 100) не удаётся найти удовлетворительное при заданной (машинной) точности значение переменной. Поэтому повысить точность вычислений попробуем также, увеличив значение опции AccuracyGoal (пример In[4]). Эта опция оказывает такое же влияние на точность вычислений, как опция PrecisionGoal — на разрядность, и точно также взаимодействует с опцией WorkingPrecision. В Out[4] получаем значение, ещё более близкое к точному.
(рис 4.11) Повышение точности некоторых вычислений при помощи опции MaxIterations
Последняя опция численных функций, с которой мы познакомимся в данной лекции, — EvaluationMonitor. Она позволяет "наблюдать" за выражением в процессе вычислений. Опишем способы её использования, предложенные П. Веллином и др. [14, с. 255–256].
Скажем, вам потребовалось получить каждое промежуточное значение выражения x, которое функция FindRoot[Cos[x],{x,2}] находит в процессе вычисления. Один из способов — выводить промежуточные значения x при помощи команды Print[x], определив её в опции EvaluationMonitor — см. пример In[1] на рис. 4.12. Однако в этом случае вы сможете только увидеть эти промежуточные значения. Для того чтобы была возможность в дальнейшем оперировать промежуточными значениями, следует прибегнуть к иному способу. Сначала нужно присвоить некоторому выражению пустой список: xtemp={}. Затем, задавая функцию FindRoot, определить для опции EvaluationMonitor следующее выражение: AppendTo[xtemp,x], — которое будет добавлять в список xtemp всё новые и новы значения x, получаемые в процессе вычисления — пример In[2]. Результат вычисления будет содержать одноуровневый список, элементами которого будут промежуточные значения вычисления итерационной функции FindRoot (Out[2]).
Подробней об управлении точностью и разрядностью вычислений см. книгу П. Веллина и др. [14, с. 254–257].
(рис 4.12) Наблюдение за процессом вычислений при помощи опции EvaluationMonitor
Зачастую пользователи работают не с отдельными числами, а с некоторым массивом данных, причём эти массивы могут быть достаточно большими, что создаёт определённые трудности в работе с ними. Mathematica использует два особых типа данных, делающих работу с массивами чисел быстрее и эффективнее, — это разреженные массивы и уплотнённые массивы.
При решении множества задач, в частности, при решении обыкновенных дифференциальных уравнений и уравнений в частных производных, больших систем уравнений, а также задач оптимизации, приходится нередко работать с матрицами высокого порядка, которые при этом содержат большое количество нулевых элементов. Подобные матрицы могут быть преобразованы в разреженные массивы — массивы, в которых не все элементы используются, имеются в наличии или нужны в данный момент; большое количество алгоритмов разработано специально для работы с такими объектами.
Разреженные массивы создаются при помощи функции SparseArray. Заданная в простейшей форме, функция SparseArray[{pos1->val1,pos2->val2,...}] генерирует массив, в котором значение pos1 занимает позицию val1, pos2 — позицию val2, и т.д., то есть, весь массив мы от начала и до конца задаём вручную, самостоятельно вводя данные. При этом размерность массива определяется автоматически: в примере In[1] на рис. 4.13 мы задаём двумерный массив, число строк которого определяется наибольшим значением первого элемента списков pos1,pos2,... (в нашем случае оно равно 3), а число столбцов, соответственно, наибольшим значением второго элемента (5 в нашем примере).
Точно такого же результата можно добиться, задав функцию в виде SparseArray[{pos1,pos2,...}->{val1,val2,...}], при этом значения val1,val2,... также занимают соответствующие позиции pos1,pos2,... — пример In[3] на рис. 4.13. При такой форме задания разреженного массива количество позиций pos должно совпадать с числом присваиваемых значений val.
В редуцированной форме функция SparseArray[{pos1,pos2,...}->val] на каждую позицию pos1,pos2,... помещает значение val.
Как разреженные массивы Mathematica рассматривает только объекты, созданные при помощи функции SparseArray. Массивы, созданные при помощи функций, с которыми мы познакомились в лекции 3, будут рассматриваться как обычные списки. Однако такие списки list можно преобразовать в разреженные массивы, применив к ним функцию SparseArray[list] — пример In[4] на рис. 4.13. Если список list является вложенным, то его внутренние списки должны иметь одинаковое число элементов, т.е., в двумерном случае list должен быть матрицей.
(рис 4.13) Задание разреженных списков
Наиболее широко употребимо задание функции в виде SparseArray[data,{d1,d2,..}], которая генерирует массив объектов размерностью d1xd2x..., причём всем позициям, значения которым не присвоены в аргументе data, присваивается значение 0. Например, в примере In[1] на рис. 4.14 мы задаём массив 4x4, диагональным элементам которого присвоено значение номера строки (или столбца, поскольку они равны), а остальным элементам — 0.
Узнать, по каким правилам присвоены значения элементам массива mass можно при помощи функции ArrayRules[mass]. В нашем примере Out[2] на рис. 4.14 мы видим, что ячейкам с конкретными номерами присвоены конкретные значения, а запись {_,_}->0 означает, что всем ячейкам, для которых никаких иных правил не задано, и присваивается значение 0.
Присваиваемое пустым (неупомянутым в аргументе data) ячейкам значение не обязательно должно быть 0: его можно определять самостоятельно при помощи третьего аргумента val0 функции SparseArray[data,{d1,d2,..},val0] — пример In[3] на рис. 4.14.
Выбирать ячейки, которым будет присваиваться значение, можно и более избирательно, задавая в аргументе data более пространные условия. Так в примере In[4] на рис. 4.14 при помощи неоднократно используемого нами условия заполнили главную диагональ числом 1, диагональ выше неё — при помощи условия ({i_,j_}/;j==i+1)->2 числом 2, а диагональ ниже — числом 3.
(рис 4.14) Задание разреженных списков. Продолжение
Разреженные массивы очень удобно и наглядно представлять графически. Для этого к разреженному массиву следует применить функцию ArrayPlot. В примере In[2] на рис. 4.15 мы графически представили небольшой квадратный массив размерностью 5x5, главная диагональ которого заполнена наибольшим в массиве числом 3, диагонали выше и ниже на одну ячейку заполнены числом 2, выше и ниже на две ячейки — числом 1, все остальные ячейки заполнены числом 0. Заметим, что чем меньше значение числа в ячейке, тем по умолчанию светлее тон, заполняющий её в графическом представлении в Out[2]. Можно также самостоятельно выбирать цвета, которые будут соответствовать заданным числам. Делается это во втором необязательном аргументе при помощи опции ColorRules. В примере In[3] мы обозначили 3 красным цветом, 2 — синим, 1 — зелёным, а 0 оставили по умолчанию белым. Помимо задания цветов вручную можно воспользоваться готовыми цветовыми схемами, с которыми мы познакомимся в лекции, посвящённой работе с графикой. Цветовые схемы задаются опцией ColorFunction. В примере In[4] мы использовали опцию в виде ColorFunction->{"Rainbow"}, задав этим радужную цветовую схему.
(рис 4.15) Наглядное представление разреженных массивов графическими средствами
К настоящему моменту мы познакомились с принципами построения разреженных массивов, научились их задавать, наглядно представлять их на экране, раскрашивая в разные цвета. Но нераскрытым до сих пор остаётся вопрос: для чего же нужно использовать разреженные массивы?
В третьей лекции сего курса мы уже познакомились со средствами задания и обработки набора числовых данных — списками. Зачем же нужно ещё одно средство, да ещё и не самое простое для понимания? Для ответа на этот вопрос воспользуемся красивым примером, который приводит в П. Веллин и др. в книге [14, с. 249–250].
Зададим в In[1] на рис. 4.16 разреженный массив размерностью 100000x100000, состоящий из случайных чисел на главной диагонали, а также на диагоналях на одну и две строчки выше и ниже; остальные ячейки имеют значение 0. В примере In[2] при помощи функции ByteCount определим объём компьютерной памяти, который занимает массив. В нашем случае он оказывается порядка 6 мегабайт. Если мы захотим задать обычный плотный массив такой же размерности известными по лекции 3 способами, где память расходуется на все элементы, включая нулевые, то путём несложных вычислений (пример In[3]) получим, что требуемый для его хранения объём компьютерной памяти окажется порядка 80 Гбайт. При попытке задать массив при помощи известной нам функции Table Mathematica выдаёт сообщение о нехватке памяти и даже останавливает ядро, поэтому для сохранения однозначности идентификации входных и выходных данных приведём этот пример последним — In[5] на рис. 4.16.
В примере In[4] на рис. 4.16 при помощи функции Timing[oper;], возвращающей время в секундах, затраченное на выполнение математической операции oper, определим время, которое на данной машине затрачивает Mathematica на нахождение скалярного квадрата заданного разреженного массива. Оказывается, что на компьютере автора курса на это действие затрачивается даже меньше секунды.
Подробней о разреженных массивах см. книгу П. Веллина и др. [14, с. 247–250].
(рис 4.16) Преимущества использования разреженных массивов
Одним из преимуществ языка программирования Mathematica является гибкость в отношении обработки данных различных типов. Например, когда пользователь выполняет расчёты с числами с плавающей запятой, Mathematica определяет тип чисел, с которыми ведётся работа, а затем определяет, следует ли пользоваться стандартным алгоритмом вычислений с машинной точностью или нужно пользоваться иным алгоритмом для осуществления вычислений с повышенной точностью. Такая самостоятельность Mathematica значительно упрощает работу пользователя, однако, за это приходится платить. Платой является необходимость хранения и использования служебной информации. В случае небольших расчётов объём служебной информации незначителен и может не приниматься во внимание, однако при работе с большими массивами данных, например, включающими десятки тысяч строк и столбцов, объём служебной информации значительно возрастает и может серьёзно тормозить вычисления. К счастью, в Mathematica имеется возможность обойтись без части служебной информации, получить ощутимый прирост скорости и уменьшить занимаемый объём памяти. Достигается это при помощи уплотнённых массивов: уплотнённый массив Mathematica представляет список однотипных (целые, вещественные, комплексные) чисел. Для иллюстрации эффекта использования уплотнённых массивов вновь воспользуемся примерами из работы П. Веллина и др. [14, с. 250–251].
В примере In[1] на рис. 4.17 зададим список случайных вещественных чисел размерностью 1000x1000. Поскольку все числа в списке одного типа (вещественные), то Mathematica автоматически рассматривает этот список как уплотнённый массив. Убедиться, является ли список list уплотнённым массивом, мы можем при помощи функции Developer`PackedArrayQ[list]. В случае если является, функция возвращает True (пример In[2]).
На основе уже имеющегося уплотнённого массива создадим неуплотнённый массив, для чего заменим один из элементов имеющегося массива числом, отличным от вещественного, например, заменим целым числом 10 число в 5 строке, 5 столбце — пример In[3] на рис. 4.17; в In[4] мы убеждаемся в том, что полученный массив не является уплотнённым (функция Developer`PackedArrayQ[list] возвращает False).
Теперь проверим при помощи уже известной нам функции ByteCount объём памяти, который занимает каждый из заданных нами массивов — пример In[5]. Первый массив, который является уплотнённым, занимает объём памяти примерно в два с половиной раза меньше, чем второй, не являющийся уплотнённым (Out[5]).
В примере In[6] на рис. 4.17 мы найдём время, затрачиваемое на нахождение максимального значения в каждом из массивов. На первый массив Mathematica затрачивает меньше миллионной доли секунды, поскольку указывает на выходе 0., во втором же на вычисления затрачивается больше сотой доли секунды.
Таким образом, работа с уплотнёнными массивами оказывается более выгодной и в плане объёма памяти, и в плане скорости вычислений.
Большинство встроенных функций организованы таким образом, что они гораздо эффективней работают с уплотнёнными массивами. Однако если время, затрачиваемое программой на обработку обычного списка, близко ко времени обработки уплотнённого массива, то функция не вынуждает Mathematica создавать уплотнённый массив, а продолжает работать с обычным списком.
Для каждой встроенной функции существует собственный минимальный размер списка, при котором он конвертируется в уплотнённый массив. Например, для функции Table это значение равно 250. Если список, заданный этой функцией, содержит число элементов, меньшее, чем 250, то он обрабатывается как обычный список, в противном случае — как уплотнённый массив (ср. примеры In[7] и In[8] на рис. 4.17). Функция Range генерирует уплотнённые массивы при любых аргументах больше 1 (пример In[9]).
Подробней о работе с уплотнёнными массивами см. книгу П. Веллина и др. [14, с. 250–253].
(рис 4.17) Преимущества работы с уплотнёнными массивами
Сколь бы ни было прекрасно работать только с точными и приближенными с высокой точностью числами, зачастую просто нет необходимости в получении сверхвысокоточных результатов. Любое число Mathematica может преобразовать в менее точное, но адекватное для дальнейших вычислений. Для этих целей в программе содержится целый ряд встроенных функций.
Функция Round[expr] по правилам математики округляет число expr до ближайшего целого. Её расширенный вариант Round[expr,a] округляет expr до ближайшего числа, нацело делящегося на a. При этом ни expr, ни a не обязаны быть целыми: они могут быть и вещественными, и рациональными, и даже комплексными. На рис. 4.18 см. примеры In[1] и In[2] использования функции округления Round.
Округление в обход математических правил позволяют совершить функции Floor и Ceiling. Первая, заданная в виде Floor[expr], возвращает ближайшее целое число, меньшее или равное expr, а Ceiling[expr] — ближайшее целое число, большее или равное expr. Расширенная форма Floor[expr,a] возвращает ближайшее число, нацело делящееся на a и меньшее expr. Соответственно, Ceiling[expr,a] возвращает ближайшее число, нацело делящееся на a и большее expr. In[3] и In[4] рис. 4.18 см. — примеры использования функций Floor и Ceiling.
Частично роль Floor берёт на себя функция IntegerPart. Заданная в единственной своей форме IntegerPart[expr] она возвращает целую часть выражения expr (пример In[5] на рис. 4.18).
Любое вещественное число expr может быть преобразовано в рациональное или целое при помощи функции Rationalize[expr] (пример In[6] на рис. 4.18).
Последней в этой лекции представим любопытную функцию Divisible[a,b], которая проверяет, делится ли нацело число a на число b, и в зависимости от результата возвращает True или False — см. пример In[7] на рис. 4.18. Функция Divisible работает корректно только в случае, если a и b являются целыми или рациональными.
Подробней об округлении чисел см. книгу Е. М. Воробьёва [1, с. 67–68].
(рис 4.18) Округление чисел
Разреженный массив — массив, в котором не все элементы используются, имеются в наличии или нужны в данный момент
Разрядность — количество значащих десятичных цифр, используемых Mathematica в представлении вещественных чисел при вычислениях.
Точность — число значащих десятичных цифр, используемых для представления дробной части вещественных чисел.
Уплотнённый массив в Mathematica — список однотипных (целые, вещественные, комплексные) чисел.
В данной лекции мы подробно познакомились с особенностями представления в Mathematica численных данных разных типов. Мы научились задавать численные данные в разных системах счисления, преобразовывать числа из одной СС в другую. Мы научились задавать и использовать случайные числа. Мы познакомились с понятиями разрядности и точности числа, узнали, каким образом Mathematica работает с приближёнными числами, научились узнавать точность и разрядность результатов вычислений и при необходимости самостоятельно задавать их. Мы научились оптимизировать ресурсоёмкие расчёты при помощи использования разреженных и уплотнённых массивов. Также мы познакомились с функциями округления приближённых чисел.
$$5^{1/2}-i$$
$$2.3+4.0i$$
$$7/6-4/i$$
Abs и Arg, найдите их абсолютные значения и углы наклона заданных ими радиус-векторов. При помощи Abs и Arg проверьте результаты, определите, к какому типу численных данных они принадлежат.Conjugate, запишите числа, комплексно сопряжённые заданным.+7, 0 и -7;+7 и -7;а, b и c;expr, заданное как expr=N[e^Pi,30], чтобы
8x8, на главной диагонали которого поместите цифры даты вашего рождения, на диагональ выше главной — число 99, на диагональ ниже главной — число 55, в остальные ячейки — число 77;Round, Floor, Ceiling, IntegerPart и Rationalize, получите число 9. Осуществите обратную операцию, получив 6.2 из 9. Выполните то же задание для любой пары чисел из следующего ряда: 1.1, 2.56, 3, 3.9, 9/5, 4.75, 5.25, 6., 6.3, 7.23, 8.4, 8.5, 9.9.Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.