Язык программирования Mathcad.
Взгляд со стороны
(статья-remake)
В.Очков
"Pergam turbare porro: ita haec res postulat"
"Буду продолжать свои выдумки - этого требует дело"
(Плавт. "Привидение", пер. с. лат.)
В конце 1995 г. на российском рынке появилась новая разработка фирмы MathSoft - шестая версия программы Mathcad (Mathcad PLUS 6.0).
Наиболее заметная “изюминка” этой версии, которую сразу оценили многочисленные пользователи Mathcad, – это встроенный язык программирования. Попробуем взглянуть на него со стороны традиционных языков программирования.
1. Немного истории
При работе с Mathcad всегда была потребность в программировании для расширения и совершенствования базового набора математических инструментов. Конкретный пример. В Mathcad есть функция
root, возвращающая корень алгебраического уравнения. Она использует метод секущих. Но есть уравнения, корень которых разумнее искать другими методами - методом Ньютона (касательных), методом половинного деления (бисекции) и т.д. Кроме того, стандартные методы Mathcad поиска корня и оптимума уравнений (функции root и minerr), решения систем алгебраических уравнений (функция find) ориентированы по точности не на значение аргумента, а на значение функции, что также нередко мешает поиску результата расчета.Эта потребность в программировании в среде Mathcad реализовалась более-менее опытными пользователями тремя путями:
Путь 1. В самых ранних версиях Mathcad были две функции
if и until, позволяющие через различные хитрости и трюки реализовывать две основные алгоритмические конструкции - выбор и повторение. Но эти функции не могут иметь в качестве аргументов блок составных операторов. Поэтому для реализации даже несложного алгоритма требовалось подключать механизм вложенных функций, что нередко превращало программу в криптограмму, в которой потом даже ее автор разбирался с трудом.Путь 2. Версии Mathcad для Windows - это полноценные Windows-приложения. Решая в среде Mathcad конкретную задачу, можно в статике (через Буфер Обменов) или в динамике (технологии DDE и OLE) перенести скаляр, вектор или матрицу в среду, например, языка fortran и решить задачу (этап задачи).
Путь 3. Начиная с пятой версии Mathcad пользователям была представлена возможность объявления в среде Mathcad новых встроенных функций. Их нужно было написать на языке С, откомпилировать каким-либо 32-разрядным транслятором и прикрепить к Mathcad через механизм DLL. Но этот путь (как, кстати, и второй) с самого начала был тупиковым. Во-первых, Mathcad создавался как инструмент решения широкого класса задач теми пользователями, кто не хотел или не умел программировать. При обращении же к языку C получалось так, что от чего ушли, к тому пришли. Во-вторых, если кто-то и переключался от работы с Mathcad к работе с языком С, то он, как правило, там и оставался, программируя целиком всю задачу. В-третьих (вернее, во-вторых с половиной), если кто-то мог на С решить свою задачу, то он обычно услугами Mathcad и не пользовался, считая это ниже своего достоинства.
2. Семерка кнопок
При первом взгляде на Mathcad PLUS 6.0 возникает удивление - почему в него был встроен не какой-либо известный и широко используемый язык, а разработан новый, ни на что не похожий. Электронные таблицы Excel 5.0, например, используют встроенный BASIC [1], и это кажется естественным даже для самых непримиримых противников этого языка. Но после детального знакомства с языком Mathcad удивление сменяется пониманием и даже удовлетворением. Становится ясным, что в рамки традиционных языков с программами в текстовом формате невозможно втиснуть богатый набор инструментария Mathcad, который реализован не только и не сколько встроенными функциями, но и в общепринятом математическом виде.
В Mathcad по сути не встроен язык программирования, а просто снято вышеотмеченное ограничение на использование составных операторов в теле алгоритмических управляющих конструкций выбор и повторение. Кроме того, добавлен цикл с параметром и оператор досрочного выхода
break, о котором подробно будет рассказано ниже (часть 7 - remake).Алгоритмические конструкции и составные операторы в среде Mathcad вводятся не традиционным набором через клавиатуру ключевых слов
IF, THEN, ELSE, WHILE и т.д., а нажимом одной из семи кнопок панели программирования:
Add Line |
¬ |
if |
while |
for |
break |
otherwise |
|
Опишем их.
Add Line
- добавить строку в программу, в тело цикла, в плечо альтернативы и т.д. Этим действием снимается ограничение на число операторов во вложенных конструкциях языка.¬
- знак присвоения. На Pascalў e мы пишем А := B + C, на BASICў е А= В + С. В языке же Mathcad А ¬ B+ С. Почему? Сначала опять приходится недоумевать, но потом понимаешь, что без знака ¬ программа превращалась бы в нечто невразумительное, бьющее в глаза программисту:A := A := B + C
В выражении же
A := A
¬ B + Cвсе ясно: локальной переменной
A присваивается (¬ ) значение суммы двух глобальных переменных B и C, значение которых где-то уже задано в документе Mathcad. Затем эта сумма передается (:=)глобальной переменной A.while
. Нажав на эту кнопку, мы получим на экране заготовку цикла с предпроверкой - слово while с двумя пустыми квадратиками:В первый квадратик (правее
while) нужно будет записать булевое выражение (переменную), управляющее циклом, а во второй (ниже while) - тело цикла. Если в теле цикла более одного оператора, то нужно воспользоваться уже описанной кнопкой Add Line.if
. Эта кнопка позволяет вводить в программу альтернативу с одним плечом. Pascal-конструкция if A > B then C := D, в среде Mathcad будет записана несколько по-еврейски: С ¬ D if A > B. Почему?! Хозяин-барин.otherwise
. Эта кнопка превращает неполную альтернативу в полную.
Pascal: |
if A > B then C := D else E := F; |
Mathcad: |
C ¬ D if A > B |
|
E ¬ F otherwise |
Слово
otherwise хоть и является синонимом слова else, но оператор otherwise не совсем одно и то же, что и ключевое слово else языка Pascal. В среде Mathcad можно написатьА := 1+2 otherwise
и сообщения об ошибке не будет. В традиционных же алгоритмических языках ключевое слово
else может стоять только в связке с if и then. В Mathcad же это не обязательно.for
. Эта кнопка позволяет вводить в программы цикл с параметром, который имеет некоторые особенности, отличающие его от аналогов в языках Pascal и BASIC. В языке Pascal цикл с параметром может иметь либо единичный (to), либо минус единичный (downto) шаг. На языке BASIC шаг может быть любым (step ...); если он не указан, то он по умолчанию единичный. Если в среде Mathcad шаг в цикле с параметром не указан, то он может быть равен либо единицеfor i О 1 .. 10
либо минус единице
for i О 10 .. 1
Аналоги цикла с параметром среды Mathcad следует искать не в языках Pascal и BASIC, а в языке C.
break
. Кнопка досрочного выхода из программы или цикла. О ней разговор особый.Ниже приведены примеры программ в среде Mathcad.
Общие замечания.
Язык программирования Mathcad по своей идеологии очень похож на язык FRED интегрированного пакета Framework
. Говорят, что один из погорельцев фирмы Ashton-Tate (разработчик Framework) перешел в фирму MathSoft и приложил руку к созданию языка программирования Mathcad. Внешне же своими вертикальными линиями, фиксирующими начало, конец и глубину вложений конструкций программы, Mathcad напоминает алгоритмические конструкции книги А.П.Брудно “Программирование в содержательных обозначениях” (М.: ”Наука”, 1968). Автор этой статьи в также увлекался подобными линиями, втискивая программы в рамки структурных диаграмм (см., например, книгу “128 советов начинающему программисту” М.: Энергоатомиздат, 1991).Линии программ Mathcad более наглядны (особенно для обучения структурному программированию), чем операторные скобки традиционных языков -
begin-end на языке Pascal, фигурные скобки на языке С, оператор list на языке FRED и т.д.3. Программа-константа, программа-переменная, программа-функция
Автор в свое время [2] сетовал на то, что в среде Mathcad нельзя группу формул заключить в рамки цикла, чтобы можно было, например, реализовать метод последовательных приближений в автоматическом режиме, без ручного переноса значения последнего приближения в голову расчета. Хоть в Mathcad и введен язык программирования с циклами, но положения статьи [2] остаются в силе: программирование в Mathcad ограничивается либо формированием сложной формулы для расчета переменной (константы), которую потом можно вставлять в выражения (программа 1), либо заданием функции пользователя (программа 2). Третья возможность (см. сноску 3) - это использование программирования для формирования оператора пользователя. Но, как понимает читатель, функция отличается от оператора лишь внешне: можно написать
add(A, B), но лучше A + B. Mathcad тем и хорош, что позволяет записывать задачу в общепринятой математической нотации.Программа 1
Программа 2
4. Скаляр - вектор - матрица
Эта тройка (опять смотри сноску 3) переменных может задаваться и программно. Формирование скаляра уже проиллюстрировано программами 1 и 2. Программы 3 и 4 формируют вектор и матрицу, соответственно. Функция - это переменная, заготовленная впрок: в среде Mathcad можно формировать не только простые, но и индексные (в виде вектора или матрицы) функции:
y(x)0, y(x)1, y(x)2 и т.д.Программа 3
Программа 4
Переменные в Mathcad теперь могут быть локальными, самообъявляющимися в программах (как, например, переменные
i и j в программе 4) и пропадающими по выходу из нее. Кроме локальной и глобальной переменной, значение которой задано вне программы и автоматически проникающее в нее, в среде Mathcad есть и системные, (предопределенные) переменные и константы. Пример - число e или p , значение которых определено самой системой (математикой), а не пользователем. Бог любит троицу - см. сноску 3.5. Рекурсия
Языки программирования обычно проходят три стадии:
1. Рекурсия невозможна
2. Рекурсия неразрешена, но применяется по принципу “Если нельзя, но очень хочется, то можно”
3. Рекурсия разрешена
Mathcad вторую стадию успешно проскочил.
И вот уже трещат морозы
И серебрятся средь полей...
(Читатель ждет уж рифмы розы
;На, вот возьми ее скорей!)
Читатель ждет уж примеров рекурсии в среде Mathcad? Скорее всего нет. Они ему оскомину набили. Но мы попробуем чего-нибудь свеженького. Например, ретроспективную рекурсию
.Как запомнить число
e (основание натурального логарифма) c десятью цифрами после запятой? Очень просто: две целых семь десятых плюс два раза Лев Толстой - 2.718281828, то есть к числу 2.7 нужно прибавить два раза год рождения писателя. Остается только самая малость - запомнить, в каком году родился Лев Толстой, или, на худой конец, сообразить, что это случилось в прошлом веке, чтобы вспомнить хотя бы три знака числа e после запятой: 2.718. Ретроспектива, обращенная в 19-й век, поможет запомнить довольно-таки точное значение одной из фундаментальных констант математики.Как запомнить, что факториал нуля равен не нулю (типичная ошибка), а единице? Очень просто. Нужно применить ретроспективный
метод поиска факториала числа: сообщить машине факториал какого-либо положительного числа N (5!=120, например) и то, что факториал предыдущего числа N-1 равен факториалу первого (N!), разделенному на N. Факториал пяти (120) - это такая же тривиальная истина, как и то, что Лев Толстой родился в девятнадцатом веке.В среде Mathcad, работая по программе 5, можно не только правильно определить факториал нуля (единица), но и получить факториалы отрицательных чисел. Машину нужно только обучить этому - заложить в программу ретроспективную рекурсию для поиска факториала на всем целочисленном диапазоне.
Программа 5
В 1202 году Леонардо Пизанский (1180-1240) описал одну из самых первых моделей развития замкнутой биологической системы, населенной условными кроликами. Если соответствующим образом определить их плодовитость и долголетие, то численность популяции кроликов будет меняться из поколения в поколение по строгому закону:
Поколение |
... |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
... |
Число кроликов |
... |
3 |
5 |
8 |
13 |
21 |
34 |
55 |
89 |
... |
Читатель, конечно, уже догадался, что речь пойдет о числах Фибоначчи - Леонардо Пизанский более известен под именем Фибоначчи (Fibonacci - сокращение от filius Bonacci - сын Боначчи). Приведенный ряд специально начат не с традиционного места (первое поколение), а с четвертого поколения для того, чтобы задать читателю вопрос, подобный тому, какой стоял в задаче о факториале: "Чему равно минимальное число кроликов в популяции - каково наименьшее число Фибоначчи?" Нормальный ответ, приводимый во всех учебниках, -
ноль. Но не будем спешить и напишем программу 6 с двухсторонней рекурсией, взяв за базовые числа Фибоначчи не традиционную пару 0 и 1, а 3 и 5.Программа 6
Про кроликов Фибоначчи со временем забыли, но числа Фибоначчи в наше время широко применяются в вычислительной математике для иллюстрации рекурсии как, например, в нашей статье.
6. Размерность
Программа по знаменитой формуле Н.Вирта - это сумма алгоритма и структуры данных. Алгоритм программы в среде Mathcad задается нажатием на клавиатуру из семи кнопок (см. выше), отвечающих за циклы и альтернативы. Структура данных в среде Mathcad также проста. Там нет ни текстовых, ни булевых, ни других экзотических переменных. Есть только числовые переменные двойной точности, которые предстают перед пользователем в комплексном
, вещественном или целочисленном виде. Они могут группироваться в векторы и в матрицы. Булевые переменные в среде Mathcad, как и в языке BASIC, хранят целочисленные значения 1 (Да, Thrue) или 0 (Нет, False):1 >2 = 0
1 < 2 = 1 и т.д.
Тип переменной в среде Mathcad в какой-то мере заменяется понятием размерности хранимой величины, что очень удобно в инженерных расчетах. По программе 7 рассчитывается площадь треугольника формированием функциии пользователя с именем Площ_треуг и вызовом ее. Аргументы функции Площ_треуг могут быть величины с разной размерностью длины (метры- m, сантиметры -cm, дюймы - in и т.д.). Система Mathcad сама в них разберется, сделает нужные пересчеты и выдаст правильный результат в выбранной пользователем системе единиц (кг-м-секунда, г-см-секунда, британская и т.д.).
Программа 7
Система Mathcad ведет контроль размерностей и не позволяет складывать, например, метры с килограммами.
Решая в среде Mathcad задачу, можно отвлечься от конкретных размерностей (кг
, м, с и т.д.), но, тем не менее, вести контроль размерностей, дополняя ввод значения переменной указанием к какой физической величине она относится (масса, длина, время и т.д.) :m:=10M a:=2L t:=5T и т.д.
Переменные M, L и T, а также G и K можно считать системными (предопределенными), хранящими единичные значения основных физических величин (G - заряд, K- абсолютная температура, остальное - см. выше). Этой компании не хватает количества вещества и силы света, чтоб превратиться в семерку (см. сноску 3).
7. Ramake
Старая песня на новый лад. Так можно перевести английское слово
remake. Прием remake особо популярен в кинематографе. Берется старый фильм, вернее, старый уже отснятый сценарий, по которому снимается новая версия кинокартины. Технология remake применяется и в программировании, когда, например, DOS-овская версия какой-либо программы переписывается для Windows.В седьмой части статьи автор в стиле remake расскажет о недостатках языка Mathcad.
Почему о недостатках?!
О достоинствах итак было и будет еще сказано немало.
Почему remake?!
Во-первых, у автора сохранился файл с текстом статьи “Turbo Pascal 7.0. Взгляд со стороны” (КомпьютерПресс, N 7, 1993), которая и подвергается remake’у. Во-вторых, язык Mathcad как и язык Pascal оказался окутан паутиной старых догм структурного программирования, о которых писалось в первой статье. Это делает remake не только простым, но и уместным и естественным.
Итак, remake.
Попробуем на простых примерах доказать, что ввод в язык Mathcad конструкции
break (см. выше) - это только полшага в сторону повышения гибкости управляющих конструкций этого языка программирования.' Программа 8. Метод Ньютона-1 (QBasic)
DEF FN
y (x) = x ^ 2 - 3 ’ функцияDEF FN
Dy (x) = 2 * x ’ ее производнаяTOL = .001
INPUT
"X начальн."; xDO
x1 = x - FNy(x) / FNDy(x)
IF ABS(x1 - x) <= TOL THEN EXIT DO
x = x1
LOOP
PRINT "Y=0 при X ="; x
END
На листинге 8 приведена QBasic-программа поиска корня алгебраического уравнения методом Ньютона (касательных). Почему мы начали с QBasic'а, хотя статья посвящена языку Mathcad. Дело в том, что язык QBasic кроме традиционной тройки циклов (цикл
с предпроверкой, цикл с постпроверкой, цикл с параметром) имеет и цикл с выходом из середины: DO [...] IF ... THEN [...] EXIT DO [...] LOOP. Эта конструкция, наряду с другими преимуществами, о которых будет сказано ниже, позволяет реализовывать алгоритмы в их естественной последовательности. Так в программе 8 объявляются и создаются функции пользователя (анализируемое уравнение y и его производная Dy), запрашивается значение начального приближения к корню x и задается значение погрешности TOL. После этого организуется цикл, но не традиционный, а с выходом из середины. В цикле, следуя естественному порядку алгоритма Ньютона, рассчитывается новое приближение к корню (x1) и, если оно отстает от предыдущего не более чем на величину заданной погрешности, то задача считается решенной (EXIT DO). Если нет, то ведется подготовка к новому приближению (x = x1), а цикл повторяется (LOOP).При реализации на языке Mathcad этот несложный алгоритм обрастает "архитектурными излишествами", т.к. его приходится запихивать в прокрустово ложе цикла
while - см. листинг 9.Программа 9
Цикл с предпроверкой (
while) требует, чтобы булевое выражение заголовка было определено еще до входа в цикл, а этого нет при поиске корня методом Ньютона. Для таких ситуаций предусмотрен цикл с постпроверкой, а его нет в языке Mathcad. Приходится до входа (и для входа) в цикл писать x1 ¬ x+2· TOL. Подобным образом лгут детям (а машина - тоже дитя), заставляя их что-то делать. Строку x1 ¬ x+2· TOL можно уподобить стартеру двигателя внутреннего сгорания, работающего, кстати, как и программа 9 циклически. Вот какими аллегориями - дитя, двигатель - обросла наша простенькая программа из-за того, что на языке Mathcad нет цикла с выходом из середины.Cтроку
x1¬ x+2 Ч TOL
обычно заменяют на строку
x1 ¬
но это тоже не оптимальное решение: “Не упоминай имя Божье и не вызывай функцию всуе “.
Можно отметить и другую ненатуральность программы 9 - постановку телеги впереди лошади: в цикле сначала приходится готовиться к новому приближению (x
1 ¬ x), хотя еще не ясно, понадобиться оно или нет, а только потом проводить его.Конструкция
break, введенная в Mathcad, призвана вернуть программе 2 ее естественность, но...Программа 10
QBasic-конструкция
DO ... LOOP (см. листинг 8) на листинге 10 превратилась в конструкцию while 1 ..., которую на латинский язык можно перевести как "ad calendas greaces" - "до греческих календ". Пришлось в программе 10 как и в программе 9 идти ну не на обман, так на натяжку: "выполняй, пока рак на горе не свистнет".История с вводом в Mathcad конструкции
break подтверждает старую истину о том, что "нет ничего практичнее хорошей теории". И вот почему.Вышеприведенный анализ циклов на языке Mathcad имеет не только сугубо практический, но и чисто теоретический аспект. Как известно, набор управляющих конструкций любого структурного языка ведет свою родословную от основной структурной теоремы Э.Дейкстры, объявившей войну меткам: "Алгоритм любой сложности можно реализовать, используя только цикл
while и альтернативу". Автор затратил уйму времени и сил в поисках статьи или книги с доказательством этой теоремы, но так и не нашел его. А вот показать, что эта теорема не верна, можно в два счета - см. листинги 11 и 12. Эти программы решают уже известную нам задачу о корне алгебраического уравнения, но другим методом - методом половинного деления. Его алгоритм - это простейшая иллюстрация теоремы Дейкстры: цикл (while) приближения к корню с вложенной альтернативой (... if ... otherwise). Если корень правее центра интервала x1 - x2, то к нему (к центру) подтягивается левый край (x1¬ x), нет - правый (x2¬ x). В программе 12 альтернатива программы 11 заменена на два цикла while, операторы тела которых попеременно выполняются либо раз, либо ни разу, что регулируется переменной Flag.Программа 11
Программа 12
В аналогичной QBasic-программе (листинг 13) также обошлись без альтернативы. Более того, удалось избавиться и от переменной-диспетчера
Flag, заменив два цикла while на один цикл, но с двумя выходами из середины - с одним условным, а вторым безусловным.' Программа 13. Метод половинного деления-3 (QBasic)
DEF FN
y (x) = x ^ 2 - 3 ‘ функцияTOL = .001
INPUT "X1, X2"; x1, x2
DO
IF ABS(x1 - x2) <= TOL THEN EXIT DO
x = (x1 + x2) / 2
DO
IF SGN(FNy(x1)) = SGN(FNy(x)) THEN x1 = x: EXIT DO
x2 = x: EXIT DO
LOOP
LOOP
' Конец циклаEND
Весь фокус программ 12 и 13 в том, что альтернатива - это средство ускоренного "путешествия" по алгоритму только в одну сторону (сверху вниз и слева направо, если смотреть на листинг), а цикл - в обе. Отсюда и ненужность (в теоретическом плане, конечно, а не в практическом) альтернативы. Цикл
DO [...] IF ... THEN [...]EXIT DO [...] LOOP можно считать гибридом цикла и альтернативы.Доказательством теоремы Э.Дейкстры может служить факт, что до сих пор не было случая, когда задуманный алгоритм нельзя было бы реализовать, используя только цикл и альтернативу. Если альтернативу исключить, то основная структурная теорема должна звучать так: "Алгоритм любой сложности можно реализовать, используя только циклы (цикл
repeat ... if ... then ... break; [if ... then ... break;],,, ... until)". Вот это-то теоретическое положение вводом процедуры break и подсовывают задним числом языки программирования Mathcad и Pascal под свой фундамент. Обращаю внимание на несовершенную форму глагола - "подсовывают", а не "подсунули" - цикл с выходом из середины на языке Mathcad осуществим через насилие над циклом while (листинг 3).Теорему Э.Дейкстры следует "понизить в звании" и называть леммой, т.е. вспомогательной теоремой, служащей для доказательства основной.
Здесь мы вернулись к спорам, бушевавшим лет 30 назад. Процедура
break, введенная в язык Mathcad, дала нам повод напомнить о них.Вернемся к практическим заботам.
Пользователям Mathcad, кодируя даже несложную программу, все время придется волей-неволей доказывать основную структурную теорему - втискивать свой алгоритм в узкие рамки цикла
while и альтернативы. Непонятно, почему в Mathcad ввели цикл for, который несложно заменить тем же циклом while. По-видимому, для того, чтобы кнопок на панели программирования было ровно семь. Программисту очень не будет хватать цикла с постпроверкой, расширенного множественного ветвления и даже метки [3]. И все из-за того, что разработчики Mathcad ориентируются на принципы программирования двадцатилетней давности - теорема Дейкстры всесильна потому, что она верна.Литература: