close

Вход

Забыли?

вход по аккаунту

Дудоров Кирилл Александрович. Разработка программы формирования полиномов для воспроизведения функций действительного переменного

код для вставки
АННОТАЦИЯ
ВКР 112 с., 60 рис., 1 табл., 17 источников, 1 прил.
ПОЛИНОМ,
МНОГОЧЛЕН,
ПОЛИНОМИАЛЬНАЯ
АППРОКСИМАЦИЯ,
СИСТЕМА
ПОЛИНОМИАЛЬНОЙ
АППРОКСИМАЦИИ,
ФОРМИРОВАНИЕ
ВОСПРОИЗВЕДЕНИЕ
ФУНКЦИЙ
ПОЛИНОМОВ,
ДЕЙСТВИТЕЛЬНОГО
ПЕРЕМЕННОГО, ВОСПРОИЗВЕДЕНИЕ ФУНКЦИЙ.
Выпускная
программы
квалификационная
формирования
полиномов
работа
посвящена
для
воспроизведения
разработке
функций
действительного переменного.
В первой главе выпускной квалификационной работы проведен анализ
существующих аналогичных систем полиномиального моделирования, а
также определены требования к разрабатываемой программе.
Во второй главе выпускной квалификационной работы рассмотрены
способы полиномиальной аппроксимации, их особенности и ограничения.
В третьей главе выпускной квалификационной работы спроектирована
структура
программы,
основные
алгоритмы
и
типы
данных,
пользовательский интерфейс программы, а также проведена реализация
программы
формирования
полиномов
для
воспроизведения
функций
действительного переменного.
В четвертой главе выпускной квалификационной работы проведено
экспериментальное формирование воспроизводящего функцию полинома в
разработанной программе и зафиксированы результаты, на основе которых
сделан вывод о достижении цели выпускной квалификационной работы.
4
СОДЕРЖАНИЕ
ВВЕДЕНИЕ
6
1 АНАЛИЗ ПРЕДМЕТНОЙ ОБЛАСТИ
8
1.1 Обзор аналогов
8
1.1.1 Система компьютерной алгебры Mathcad
8
1.1.2 Пакет прикладных математических программ Scilab
12
1.1.3 Вывод о существующих аналогах
19
1.2 Требования к программе
20
2 ИССЛЕДОВАНИЕ СПОСОБОВ ПОЛИНОМИАЛЬНОЙ
АППРОКСИМАЦИИ
23
2.1 Линейная интерполяция
23
2.2 Интерполяция полиномами Ньютона
24
2.3 Интерполяция многочленами Лагранжа
24
2.4 Сплайн-интерполяция
24
2.5 Вывод об исследованных способах полиномиальной аппроксимации
25
3 РАЗРАБОТКА ПРОГРАММЫ ФОРМИРОВАНИЯ ПОЛИНОМОВ ДЛЯ
ВОСПРОИЗВЕДЕНИЯ ФУНКЦИЙ ДЕЙСТВИТЕЛЬНОГО ПЕРЕМЕННОГО
26
3.1 Описание вариантов использования программы
26
3.2 Структура программы
28
3.3 Описание основных алгоритмов
31
3.3.1 Подсистема пользовательского интерфейса
31
3.3.2 Подсистема исходной функции
36
3.3.3 Подсистема аппроксимирующего полинома
42
3.3.4 Файловая подсистема
50
3.4 Проектирование структур данных
52
3.5 Проектирование интерфейса
53
3.6 Реализация программы
56
3.6.1 Подсистема пользовательского интерфейса
56
3.6.2 Подсистема исходной функции
58
5
3.6.3 Подсистема аппроксимирующего полинома
61
3.6.4 Файловая подсистема
63
4 ФОРМИРОВАНИЕ ПОЛИНОМА В РАЗРАБОТАННОЙ СИСТЕМЕ
65
ЗАКЛЮЧЕНИЕ
77
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ
78
ПРИЛОЖЕНИЕ А – ЛИСТИНГ ПРОГРАММЫ
80
УДОСТОВЕРЯЮЩИЙ ЛИСТ
110
ИНФОРМАЦИОННО-ПОИСКОВАЯ ХАРАКТЕРИСТИКА
ДОКУМЕНТА НА ЭЛЕКТРОННОМ НОСИТЕЛЕ
111
6
ВВЕДЕНИЕ
Современная микроэлектроника позволяет производить широкий спектр
различных
устройств,
таких как,
например,
микроконтроллеры
и
ПИД
регуляторы. При проектировании данных устройств возникает потребность в
построении
математической
модели
формируемого
устройством
сигнала.
Последовательность таких сигналов называют функцией. Построение таких
функций является важной практической задачей [1].
Функции
сигналов,
детально
и
точно
описывающие
принципы
функционирования микроэлектронных устройств, могут быть и зачастую
являются весьма сложными для анализа и практического применения. К тому же
регистрация сигналов при тестировании устройства при выполнении имеет
определенную
погрешность
распознавание
сигнала
или
шумов,
определенный
которые
могут
уровень
усложняющих
превышать
погрешности,
возникающие при определении сигналов по сложным функциям [7].
В общем случае задача моделирования сигналов состоит в поучении такой
функции сигналов, которая является удобной для восприятия и анализа [12].
Наиболее полно этому критерию удовлетворяет полиномиальная аппроксимация
– процесс формирования полиномов, воспроизводящих сложные функции сигнала
различных микроэлектронных устройств.
Сфера применения микроэлектронных устройств постоянно расширяется.
Существующие программные комплексы полиномиальной аппроксимации имеют
широкий набор различных инструментов для формирования полиномов,
воспроизводящих функции действительного переменного, однако зачастую не
имеют возможности удобного управления ходом процесса аппроксимации и
контроля всех произведенных изменений. Процесс в случае работы в этих
системах не имеет четкой последовательности и возможности наблюдения
изменений приближения полинома к функции.
Хотя проблема осуществления контролируемого процесса полиномиальной
аппроксимации
проанализирована
и
имеет
ясное
понимание
в
среде
7
проектировщиков микроэлектронных устройств и систем автоматизированного
управления, до настоящего времени не был сформирован инструментарий,
позволяющий осуществлять неавтоматическое формирование полиномов для
воспроизведения функции управляющего сигнала.
В силу указанных причин вопрос разработки программы формирования
полиномов для воспроизведения функций действительного переменного является
актуальным.
Объект исследования – системы полиномиальной аппроксимации.
Предмет
исследования
–
системы
формирования
полиномов
для
воспроизведения функций действительного переменного.
Цель исследования – сокращение времени проведения
аппроксимации
полиномиальной
с пошаговым контролем всех изменений полинома, а также
получение полинома вида [8]
U L ?Æ H : T F =; Æ E ?Æ? 5 H : T F =; Æ? 5 E fi E ?5 H : T F =; 5 E ?4 E >,
(1)
воспроизводящего исходную функцию.
Для достижения цели сформулированы следующие задачи исследования:
1. Провести анализ предметной области (рассмотреть существующие
системы
полиномиальной
аппроксимации
и
разработать
требования
к
программной системе).
2. Разработать программу формирования полиномов для воспроизведения
функций действительного переменного.
3. Провести формирование полинома для воспроизведения произвольной
функции как экспериментальную проверку работоспособности программы и
соответствия ее требованиям.
8
1 АНАЛИЗ ПРЕДМЕТНОЙ ОБЛАСТИ
1.1 Обзор аналогов
1.1.1 Система компьютерной алгебры Mathcad
Mathcad – система компьютерной алгебры, основанная принципе создания
интерактивного документа с математическими вычислениями и визуальным
сопровождением. При создании таких документов используется принцип
WYSIWYG (англ. What You See Is What You Get – «что видишь, то и
получаешь»), что обеспечивает удобную работу и возможность мгновенного
просмотра результата произведенных действий.
В данной выпускной квалификационной работе используется версия
системы Mathcad 15.0 free trial – пробная версия программы с полноценным
функционалом. На рисунке 1 представлен интерфейс программы.
Рисунок 1 – Интерфейс системы Mathcad
9
Здесь и далее для процесса формирования полинома для воспроизведения
функций действительного переменного будут использованы следующие исходные
данные:
– функция:
: T6 ; E T7 F t ;
UL
(2)
– интервал по оси OX: [-15; 25];
– шаг изменения переменной: 0,1.
Чтобы начать полиномиальную аппроксимацию, необходимо сформировать
отображение исходно функции, объявив переменную x и рассчитав значения
переменной y. Далее необходимо объявить интервал, на котором определена
переменная, и задать шаг изменения переменной. Система Mathcad сформирует
табличное отображение исходной функции (рисунок 2).
Рисунок 2 – Исходные данные и табличное отображение функции в системе
Mathcad
10
Далее необходимо сформировать графическое представление функции. Это
можно сделать с помощью инструмента «График X – Y @» в левой панели
инструментов. После заполнения всех ячеек внизу графика, а также левой средней
ячейки система автоматически отобразит график функции (рисунок 3).
Рисунок 3 – График функции в системе Mathcad
Следующим шагом станет формирование полинома с произвольными
коэффициентами. Ниже используется полином 3 степени с коэффициентами,
равными «1». Для него также необходимо задать интервал, на котором определена
переменная (рисунок 4).
Рисунок 4 – Полином и его табличное отображение в системе Mathcad
11
При добавлении полинома в график система Mathcad отобразит его
(рисунок 5).
Рисунок 5 – Графики функции и полинома в системе Mathcad
Для
более
полного
контроля
качества
проведения
аппроксимации
необходимо добавить в документ функцию ошибки, определяемую как разность
функции и полинома. Процедура добавления функции аналогична определению
исходной функции и полинома (рисунок 6).
Рисунок 6 – Табличное отображение функции ошибки и графики всех трех
функций в системе Mathcad
12
Дальнейшие действия сводятся к изменению коэффициентов полинома
таким образом, чтобы обеспечить стремление функции ошибки к оси OX, то есть
максимальное
совпадение
графиков
функции
и
полинома.
Результат
аппроксимации представлен на рисунке 7.
Рисунок 7 – Результат полиномиальной аппроксимации в системе Mathcad
Таким образом, полином, воспроизводящий исходную функцию, имеет вид:
UL sÆ
rrt H T7 F r Æ
ru H T6 F r Æ
t HTE s
(3)
1.1.2 Пакет прикладных математических программ Scilab
Scilab – пакет прикладных математических программ, имеющий большое
количество математических функций, а также возможность добавления новых.
Также в системе доступно множество инструментов, для аппроксимации,
решения дифференциальных уравнений, работы со статистикой и компьютерной
алгеброй.
В данной выпускной квалификационной работе используется версия
системы Scilab 6.0.1 – бесплатная свободно распространяемая версия программы.
На рисунке 8 представлен интерфейс системы.
13
Рисунок 8 – Интерфейс системы Scilab
Исходные данные для проведения эксперимента по формированию
полинома
для
воспроизведения
функций
действительного
переменного
идентичны представленным в разделе 1.1.1.
Чтобы начать формирование полином, необходимо определить интервал, на
котором определена переменная, а также функцию. В Командное окно вводятся
соответствующие
значения.
После
нажатия
клавиши
«Enter»
система
автоматически рассчитает и отобразит таблицы значений переменной и функции
(рисунок 9).
Все переменные и функции хранятся в Обозревателе переменных,
расположенном в правом верхнем углу главного окна программы. Также все
введенное пользователем в командное окно, также сохраняется в Журнале
команд, который находится ниже Обозревателя переменных (рисунок 10).
14
Рисунок 9 – Функция в системе Scilab
15
Рисунок 10 – Обозреватель переменных и Журнал команд в системе Scilab
Для отображения графика функции необходимо ввести команду plot(x,y) в
Командное окно. График откроется в отдельном окне (рисунок 11).
Далее необходимо сформировать полином, ориентируясь на графическое
представление функции. В данном эксперименте как начальный взять полином
третьей степени с коэффициентами, равными «1» (рисунок 12).
16
Рисунок 11 – График функции в системе Scilab
Рисунок 12 – Полином в системе Scilab
17
Командой plot(x,p) производится построение графика полинома. График
также отображается в отдельном окне (рисунок 13).
Рисунок 13 – Графики функции и полинома в системе Scilab
Для того чтобы получить наиболее близкий к функции полином,
необходимо ввести функцию ошибки, определяемую как разность функции и
полинома (рисунок 14).
Рисунок 14 – Функция ошибки в системе Scilab
Окончательное
графическое
представление
исходной
функции,
аппроксимирующего полинома и функции ошибки можно получить, введя в
Командное окно команду plot(x,y¶r¶x,p¶b¶x,err¶g¶ (рисунок.15).
18
Рисунок 15 – Графики исходной функции, аппроксимирующего полинома и
функции ошибки в системе Scilab
Дальнейшие действия сводятся к изменению коэффициентов полинома
?4 Æ
?5 Æ Æ
?Æ таким образом, чтобы обеспечить стремление разницы функции и
полинома к нулю. Результат аппроксимации представлен на рисунке 16.
Рисунок 16 – Значения коэффициентов полинома в Обозревателе переменных и
результат полиномиальной аппроксимации в системе Scilab
19
1.1.3 Вывод о существующих аналогах
Проведенные эксперименты позволили изучить программные продукты,
аналогичные разрабатываемой системе, и выделить их преимущества. Так,
системы
компьютерной
алгебры
предоставляют
пользователю
большое
количество функций и возможностей для осуществления операций в самых
разных областях математики, анализа и моделирования. Также весьма полезна
возможность тонкой настройки графических компонентов таких систем: выбор
цвета графика, стиля линии и формы точек, составляющих функцию.
Однако существующие системы полиномиальной аппроксимации имеют
ряд недостатков:
1.
Отсутствие
удобного
инструментария
для
осуществления
таких
преобразований графиков функций как вращение и сдвиг. Системы предлагают
меня уравнение функции вместо отдельной реализации описанного функционала.
2. Высокая трудоемкость и большие временные затраты для ручной
аппроксимации.
Ввод
коэффициентов
вместо
изменения
их
отдельным
инструментом увеличивает время формирования полинома.
3. Отсутствие возможности пошагового просмотра изменений. Функционал
некоторых систем можно использовать для хранения истории изменений, однако
такой способ увеличивает временные затраты на аппроксимацию и не позволяет
просматривать изменения
в графическом
виде.
Остальные
же
системы
отображают только конечный результат всех действий пользователя.
4. Отсутствие автоматически вычисляемой функции ошибки, что снижает
точной проводимой аппроксимации.
В таблице 1 приведен сравнительный анализ систем-аналогов.
Таким образом, вышеперечисленные недостатки имеющихся систем делают
очевидной потребность разработки программного инструментария формирования
полиномов для воспроизведения функций действительного переменного.
20
Таблица 1 – Сравнительный обзор систем аналогов.
Программные
системы
Scilab
+
+
+
–
–
+
–
–
+
+
–
+
–
–
+
–
–
+
Критерии
Расчет произвольной
функции
Разрабатываемая
Mathcad
система
Оперативное
графическое
отображение
произвольной
функции
Оперативное
преобразование
функций
Оперативная
корректировка вида
функции
Наличие истории
изменений полинома
Автоматический
расчет функции
ошибки
1.2 Требования к программе
Анализ предметной области и потребностей инструментария формирования
полиномов для воспроизведения функций действительного переменного выявил
следующие основные требования:
1.
Обработка
и
оперативное
графическое
элементарной функции действительного переменного.
2. Задание аппроксимирующего полинома.
представление
любой
21
3. Изменение (корректировка) аппроксимирующего полинома и функции.
4. Отображение полинома в удобном представлении.
5. Осуществление элементарных преобразований функции и полинома.
6. Ведение истории процесса аппроксимации.
7. Построение функции ошибки.
8. Сохранение результатов работы в программе.
Описанные выше требования можно детализировать следующим образом:
1. Расчет и отображение графика следующих функций:
1.1. Степенная функция вида
UL T ,
(4)
где a – любой действительный показатель степени.
1.2. Полином вида
U L ?Æ H TÆ E ?Æ? 5 H TÆ? 5 E fi E ?5 H T5 E ?4 ,
(5)
где ?4 Æ
?5 Æ Æ
?Æ – фиксированные коэффициенты полинома [11].
1.3. Рациональная функция вида
UL
:º ;
˚ :º ;
,
(6)
где 2 : T; Æ
3 : T; – полиномы.
1.4. Показательная функция вида
U L =º ,
(7)
где a – любое действительное основание степени [15].
1.5. Логарифмическая функция:
1.5.1. Натуральный логарифм вида
UL
T
(8)
1.5.2. Десятичный логарифм [16] вида
UL
T
1.6. Тригонометрические функции: синус (U L
T), тангенс (U L
T) [6].
T), котангенс (U L
T), секанс (U L
(9)
T), косинус (U L
T), косеканс (U L
22
1.7. Обратные тригонометрические функции: арксинус (U L
арккосинус (U L
арксеканс (U L
T), арктангенс (U L
T), арккосеканс (U L
T), арккотангенс (U L
косинус
(U L
гиперболический котангенс (U L
гиперболический косеканс (U L
T),
T),
T).
1.8. Гиперболические функции: гиперболический синус (U L
гиперболический
T),
гиперболический
тангенс
(U L
T), гиперболический секанс (U L
T),
T),
T),
T) [17].
2. Задание и настройка аппроксимирующего полинома вручную путем
указания или изменения его степени, а также коэффициентов.
3. Изменение коэффициентов полинома, а также его степени
4. Отображение графика полинома в указанном интервале.
5. Отображение функции полинома в текстовом виде.
6. Осуществление сдвига графика функции или полинома по осям OX и OY
относительно начала координат и поворот графика функции на заданный угол.
7. Отображение функции ошибки, позволяющей визуально определить
точность аппроксимации.
8. Отображение истории всех изменений полинома.
9. Отображение любого промежуточного графика полинома путем его
выбора в истории изменений.
10. Сохранение результатов работы в программе в файл.
11. Загрузка ранее выполненной работы в программу из файла.
23
2 ИССЛЕДОВАНИЕ СПОСОБОВ ПОЛИНОМИАЛЬНОЙ
АППРОКСИМАЦИИ
Аппроксимация или приближение – научный метод, состоящий замене
сложных
функций
более
простыми
[5].
Она
позволяет
исследовать
характеристики и свойства сигнала, сводя его функцию к более простой и
удобной для восприятия и анализа.
Разновидность аппроксимации, при которой функция проходит через
некоторые точки исходной функции, называют интерполяцией. Если некоторая
функция сигнала слишком сложна для анализа, можно попытаться вычислить ее
значение в нескольких точках, и по ним построить упрощенную функцию. Однако
данный метод не позволяет получить точные результаты, так как полученная
упрощенная функция имеет погрешности.
Далее описаны наиболее часто используемые методы полиномиальной
интерполяции.
2.1 Линейная интерполяция
Метод линейной интерполяции заключается в соединении прямой двух
точек исходной функции [5]. Геометрически это означает замену графика
исходной функции графиком алгебраического двучлена вида:
UL = H TE >
(10)
Данный метод является одним из самых простых в использовании. Также
преимуществом метода линейной интерполяции является отсутствие роста
сложности алгоритма, так как степень многочлена не зависит от степени числа
узлов.
Основной
недостаток
данного
метода
состоит
в
том,
полином,
сформированный при его использовании, отличается низкой точностью и не
отражает в необходимой степени исходную функцию.
24
2.2 Интерполяция полиномами Ньютона
Данный метод основан на приближении исходной функции многочленами
Ньютона. Основным условием выполнимости данного метода является равное
расстояние между узлами интерполяции и упорядоченность их по величине [9].
H: ? 5; H H: ? Æ> 5;
2Æ: T; L U4 E MH ¿ H U4 E fi E
где ML
º?º,
ÆŁ
H ¿ Æ H U4 ,
(11)
, U L B , ¿ H U4 – конечные разности.
Преимущество
метода
состоит
в
легкой
модификации
конечного
многочлена. Однако накладываемое на исходную функцию ограничение является
существенным недостатком данного метода.
2.3 Интерполяция многочленами Лагранжа
Данный метод основан на приближении исходной функции полиномами
Лагранжа – многочленами минимальной степени, принимающими данные
значения в данном наборе точек [14]:
. : T; L ˆ
Æ
@4 U
H: T; L ´
º?º
Æ
@4Æ• º ? º
H H: T;
(12)
(13)
Преимущество данного метода состоит в применимости для любой
функции, однако он имеет ряд недостатков. Так, при использовании метода
возрастает сложность формирования полинома. Также полученный таким образом
аппроксимирующий полином не обеспечивает высокую степень приближения.
2.4 Сплайн-интерполяция
Метод интерполяции сплайнами заключается в нахождении и дальнейшем
применении набора сплайнов – функций, область определения которых разбита
на конечное число отрезков, на каждом из которых они совпадают с некоторым
полиномом [2]:
25 : T4 ; L B: T4 ; ,
(14)
2 : T ; L 2 > 5 : T ; L B: T ; ,
(15)
2Æ: TÆ; L B: TÆ;
(16)
25
Основное преимущество данного метода – устойчивость и отсутствие
специфических условий. Недостатком является высокая сложность формирования
полинома, воспроизводящего исходную функцию, и отсутствие определенного
алгоритма моделирования. Метод также не обеспечивает высокой точности
приближения и достаточной степени гладкости полинома [10].
2.5 Вывод об исследованных способах полиномиальной аппроксимации
Проведенное
исследование
методов
полиномиальной
аппроксимации
позволяет сделать вывод об их различии и широком диапазоне сфер применения.
Каждый метод обладает как преимуществами, так и недостатками, не
позволяющими
использовать
его
в
полной
мере
для
полиномиальной
аппроксимации. Поэтому наиболее эффективным методом представляется метод
прямого описания, опирающийся на неавтоматическое формирование полиномов
для воспроизведения функций действительного переменной.
Метод позволит
осуществлять полный контроль над процессом аппроксимации и максимальную
точность приближения функции полиномом.
26
3 РАЗРАБОТКА ПРОГРАММЫ ФОРМИРОВАНИЯ ПОЛИНОМОВ ДЛЯ
ВОСПРОИЗВЕДЕНИЯ ФУНКЦИЙ ДЕЙСТВИТЕЛЬНОГО
ПЕРЕМЕННОГО
3.1 Описание вариантов использования программы
Возможности программы и взаимодействие ее с пользователем удобно
описывать с помощью диаграммы вариантов использования. Она является
концептуальной моделью разрабатываемой программы в процессе ее разработки.
Построение диаграммы вариантов использования начинается с выделения
актёров (акторов) – ролей, исполняемых при взаимодействии с вариантами
использования системы [4]. Для программы формирования полиномов для
воспроизведения функций действительного переменного удобно выделить актора
«Пользователь».
В ходе разработки программы были выявлены следующие варианты
использования:
1. Ввод функции.
2. Изменение функции.
3. Изменение интервала функции.
4. Сдвиг функции.
5. Вращение функции.
6. Формирование полинома.
7. Изменение полинома.
8. Изменение интервала полинома.
9. Сдвиг полинома.
10. Вращение полинома.
11. Изменение коэффициентов полинома.
12. Изменение степени полинома.
13. Выбор пункта истории изменений полинома.
14. Открытие файла.
27
15. Сохранение файла.
16. Получение информации о программе.
Диаграмма вариантов использования приведена на рисунке 17.
Между актёром и вариантами использования «Выбор пункта истории
изменений полинома», «Открытие файла», «Сохранение файла», «Получение
информации
о
программе»,
«Ввод
функции»,
«Изменение
функции»,
«Формирование полинома», «Изменение полинома», «Выбор пункта истории
изменений полинома» установлено отношение ассоциации. Это означает, что
актер напрямую инициирует соответствующие варианты использования.
Между вариантами использования «Изменение функции» и «Изменение
интервала функции», «Сдвиг функции», «Вращение функции», а также между
вариантами «Изменение полинома» и «Изменение интервала полинома»,
«Вращение полинома», «Сдвиг полинома» установлено отношение включения.
Это означает, что данные действия становятся доступны при выполнении
включаемого варианта использования.
Между
вариантами
использования
«Изменение
полинома»
и
«Формирование полинома», а также между вариантами «Изменение функции» и
«Ввод функции» установлено отношения расширения. Это означает, что
функционал вариантов «Изменение полинома» и «Изменение функции» может
быть дополнен.
Между
«Изменение
вариантами
степени
использования
полинома»,
«Формирование
«Изменение
полинома»
коэффициентов
и
полинома»
установлено отношение общения. Это означает, что варианты использования
«Изменение степени полинома» и «Изменение коэффициентов полинома»
являются специализацией, и их можно обобщить в вариант «Формирование
полинома».
28
Рисунок 17 – Диаграмма вариантов использования программы
3.2 Структура программы
Программа формирования полиномов для воспроизведения функций
действительного переменного построена на основе комбинирования объектноориентированного и процедурного подходов. Так, основной функционал
реализован в виде классов, а часть инструментов, использующихся дл обработки
исходной функции, а также вспомогательные структуры данных, используемые в
классах для реализации функционала, – в виде модулей. Такая структура
позволяет организовать гибкую систему и исключить дублирование структур
данных, использующихся в нескольких классах.
Программу формирования полиномов по реализуемому функционалу
можно разбить на несколько подсистем:
29
1. Подсистема пользовательского интерфейса.
2. Подсистема исходной функции.
3. Подсистема аппроксимирующего полинома.
4. Подсистема работы с файлами.
Подсистема пользовательского интерфейса включает в себя главное окно, а
также дополнительное справочное окно. Модуль главного окна реализует
основные аспекты взаимодействия с пользователем, а также является связующим
элементом всех подсистем программы. В главном окне находятся все элементы
управления, а также поля вывода всей необходимой информации. Справочное
окно отображает название программы, краткое описание ее задач, а также версию
программы и информацию об авторе.
Подсистема
исходной
функции
включает
в
себя
интерпретатор
математических выражений и блок операций над функцией. Интерпретатор
приводит текстовый вид функции, удобный для восприятия пользователем, в
форму, используемую внутри системы для работы с этой функцией – абстрактное
синтаксическое дерево. Состоит из следующих блоков:
1. Лексический анализатор, преобразующий функцию в текстовом виде в
поток токенов – идентифицированных последовательностей символов входного
выражения.
2.
Синтаксический
анализатор,
который
генерирует
абстрактное
синтаксическое дерево из полученных лексическим анализатором токенов на
основе структуры исходной аппроксимируемой функции.
Блок операций над функцией использует полученное в результате
трансляции абстрактное синтаксическое дерево для выполнения операций расчета
множества точек функции в заданном интервале переменной, сдвига по осям OX
и OY относительно начала координат, а также поворота.
Подсистема аппроксимирующего полинома включает в себя два блока:
1. Блок формирования полинома. Формирует внутреннее представление
полинома на основе его степени и списка коэффициентов. Также отвечает за
построение полинома в текстовой форме в виде суммы одночленов.
30
2. Блок операций над полиномом. Реализует операции расчет множества
точек полинома в заданном диапазоне переменной, поворота полнома, а также его
сдвига по осям OX и OY относительно начала координат.
Файловая подсистема отвечает за сохранение результатов работы в
программе в файл и загрузки ранее произведенных действий из файла в
программу.
Подсистемы исходной функции и аппроксимирующего полинома не
взаимодействию друг с другом, осуществляя обмен данными только с
подсистемой
пользовательского
интерфейса.
Файловая
подсистема
не
взаимодействует с ними напрямую, запрашивая или передавая данные через
подсистему пользовательского интерфейса.
Структура разрабатываемой программы представлена на рисунке 18.
Рисунок 18 – Структура программы формирования полиномов для
воспроизведения функций действительного переменного
31
3.3 Описание основных алгоритмов
3.3.1 Подсистема пользовательского интерфейса
Подсистема взаимодействия с пользователем включает в себя главное окно
программы и справочное окно. В главном окне определены элементы
пользовательского интерфейса программы, а также алгоритмы их обработки и
взаимодействия с пользователем.
При запуске программы происходит настройка ее подсистем и активация
всего имеющегося функционала. Алгоритм настройки выглядит следующим
образом:
1. Очистить все поля главного окна.
2. Установить размеры ячеек таблицы коэффициентов полинома и
количество ее столбцов.
3. Установить размеры ячеек таблицы истории изменений полинома.
4. Активировать весь инструментарий программы и обеспечить к нему
доступ из главного окна.
5. Создать новый файл для работы в программе.
При закрытии программы происходит ряд действий, связанныех с
предложением сохранить файл и подтверждением завершения работы в
программе. Алгоритм закрытия программы:
1. Проверить, был ли сохранен файл. Если файл был сохранен, то переход к
шагу 5, иначе переход к шагу 2.
2. Предложить пользователю сохранить результаты работы в программе в
файл.
3. Если пользователь решил сохранить файл, то переход к шагу 4. Иначе
переход к шагу 6.
4. Сохранить файл.
5. Уточнить у пользователя, желает ил он выйти из программы. Если
желает, то переход к шагу 6, иначе конец алгоритма.
6. Закрыть программу
32
Схема алгоритма закрытия программы приведена на рисунке 19.
Рисунок 19 – Схема алгоритма закрытия главного окна
33
При создании нового файла происходит инициализация полей начальными
значениями, а также установка имени нового файла. Алгоритм, представляющий
эти действия, описан следующим образом:
1. Проверить, был ли файл сохранен. Если файл не был сохранен, то
переход к шагу 2, иначе переход к шагу 5.
2. Предложить пользователю сохранить файл.
3. Если пользователь выбрал сохранение файла, то переход к шагу 4, иначе
переход к шагу 5.
4. Сохранить результаты работы в программе в файл.
5. Записать в поля программы стандартные значения.
6. Сгенерировать и записать имя нового файла.
Схема алгоритма создания нового файла представлена на рисунке 20.
Рисунок 20 – Схема алгоритма создания нового файла
34
Программа также предоставляет возможность открытия ранее созданного
файла. Алгоритм открытия файла, производящий загрузку сохраненных данных в
программу, состоит из следующих шагов:
1. Проверить, был ли файл сохранен. Если файл не был сохранен, то
переход к шагу 2, иначе переход к шагу 5.
2. Предложить пользователю сохранить файл.
3. Если пользователь выбрал сохранение файла, то переход к шагу 4, иначе
переход к шагу 5.
4. Сохранить результаты работы в программе в файл.
5. Загрузить требуемый файл.
6. Заполнить поля программы содержимым файла.
7. Рассчитать функцию и построить ее график.
8. Рассчитать полином и построить его график.
Схема алгоритма открытия файла представлена на рисунке 21.
Рисунок 21 – Схема алгоритма создания нового файла, лист 1
35
Рисунок 21, лист 2
Алгоритм сохранения файла производит сохранение результатов работы в
программе в файл, имя которого задано пользователем.
1. Записать в файл параметры функции: интервал, величины свдига и
поворота.
2. Записать в файл параметры полинома.
3. Запись в файл тесктового представления функции.
4. Запись в файл текстового представления полинома.
36
Окно «О программе» отображает название программы, версию системы, ее
автора, а также краткое описание предназначения программы. Алгоритм работы
справочного окна включаетв себя следущие шаги:
1. Отобразить название программы.
2. Отобразить краткое описание программы.
3. Отобразить версию программы.
4. Отобразить информацию об авторе.
3.3.2 Подсистема исходной функции
Подсистема
исходной
функции
включает
в
себя
инструментарий,
позволяющий производить операции над функцией. Она состоит из модулей,
отвечающих за трансляцию текстового представления функции, а также
алгоритмов, реализующих работу с функцией: ее расчет при заданном значении
переменной, а также сдвиг по осям OX и OY относительно начала координат и
поворот.
Интерпретатор математических выражений и функций – важнейшая часть
системы
формирования
действительного
полиномов
переменного.
Он
для
воспроизведения
функций
преобразовать
строковое
позволяет
представление функции в форму, удобную для ее расчета и выполнения
преобразований – абстрактное синтаксическое дерево.
Лексический анализ аппроксимируемой функции основан на механизме
конечных автоматов. Анализатор, обрабатывая символ, переходит по нему в
новое состояние. Процесс перехода продолжается до тех пор, пока не будет
достигнуто одно из финальных состояний. Каждому из таких состояний
соответствует токен, который модуль анализатора передает на следующий этап
трансляции. Детерминированный конечный автомат лексического анализатора
программы
формирования
полиномов
для
воспроизведения
функций
действительного переменного представлен на рисунке 22
Синтаксический
восходящий
алгоритм
анализ
аппроксимируемой
синтаксического
разбора
функции
LALR(1),
использует
использующий
37
множества терминалов и таблицу разбора. Множество функций и операцию над
ними и вещественными числами описано с использованием механизма
контекстно-свободных грамматик. Каждому правилу грамматики ставится в
соответствие набор действий, которые выполнит синтаксический анализатор при
достижении правила.
Рисунок 22 – Детерминированный конечный автомат лексического анализатора
программы
38
Для упрощения восприятия и анализа представленный выше граф
детерминированного конечного автомата можно обощить, сгруппировав лексемы
по следующим категориям:
1. Вещественное число.
2. Переменная.
3. Арифметическая операция.
4. Функция.
5. Круглые скобки.
Обощенная схема детерминированного конечного автомата лексического
анализатора программы представлена на рисунке 23.
Рисунок 23 – Схема конечного автомата программы
Интерпретатор
генерирует
абстрактное
синтаксическое
дерево
как
результат разбора функции. Далее описаны алгоритмы работы с деревом.
Алгоритм создания нового узла дерева:
1. Создать новый пустой дочерний узел дерева.
2. Сохранить в узле дерева его тип и значение.
Алгоритм
переменной:
вычисления
значения
функции
при
заданном
значении
39
1. Если абстрактно-синтаксическое дерево функции пусто или не
существует, то конец алгоритма. Иначе переход к шагу 2.
2. Если узел дерева является переменной, то переход к шагу 3, иначе
переход к шагу 4.
3. Результатом работы алгоритма является значение переменной. Затем
конец алгоритма.
4. Если узел дерева хранит вещественное число, то переход к шагу 5, иначе
переход к шагу 6.
5. Результатом работы алгоритма является содержащееся в узле дерева
число. Затем конец алгоритма.
6. Если в узле дерева содержится арифметическая операция, то переход к
шагу 7, иначе переход к шагу 12.
8. Принять левый дочерний узел текущего узла как текущий узел. Далее
выполнить шаги 1 – 13.
9. Принять правый дочерний узел текущего узла как текущий узел. Далее
выполнить шаги 1 – 13.
10. Применить арифметическую операцию к результатам шагов 8 и 9.
11. Результатом работы алгоритма является полученное в пункте 10
вещественное число. Затем конец алгоритма.
12. Если узел дерева хранит информацию о функции, то переход к шагу 13,
иначе конец алгоритма.
13. Результатом работы алгоритма является применение функции к
значению. Затем конец алгоритма.
Схема алгоритма вычисления значения функции при заданном значении
переменной представлена на рисунке 24.
Алгоритм вычисления функции на заданном интервале:
1. Определить количество рассчитываемых точек функции.
2. Пока значение переменной находится в пределах интервала, повторять
шаги 3 – 4. Затем конец алгоритма.
3. Вычислить значение функции при заданном значении переменной.
40
4. Вычислить новое значение переменной.
Схема алгоритма приведена на рисунке 25.
Рисунок 24 – Схема алгоритма вычисления значения функции при заданном
значении переменной
41
Рисунок 25 – Схема алгоритма вычисления функции на заданном интервале
Алгоритм сдвига функции по осям OX или OY относительно начала
координат:
1. Для каждой точки функции повторять шаги 2 – 3. Затем конец алгоритма.
2. Вычислить свдиг точки по оси OX.
3. Вычислить сдвиг точки по оси OY.
Схема алгоритма представлена на рисунке 26.
Алгоритм поворота функции на произвольный угол:
1. Перевести градусы в радианы.
2. Для каждой точки функции повторять шаги 3 – 4. Затем конец алгоритма.
3. Вычислить новую координату x точки после поворота.
4. Вычислить новую координату y точки после поворота.
Схема алгоритма представлена на рисунке 27.
42
Рисунок 26 – Схема алгоритма сдвига функции
Рисунок 27 – Схема алгоритма поворота функции
3.3.3 Подсистема аппроксимирующего полинома
Подсистема работы с полиномом включает в себя модуль операций
создания полинома и вычисления его значения в заданной точке, а также модуль
получения полинома в табличном виде. Далее описаны алгоритмы, описывающие
функционал этих модулей.
43
Алгоритм
вычисления
значения
полинома
при
заданном
значении
переменной:
1. Если количество коэффициентов полинома равно единице, то переход к
шагу 2, иначе переход к шагу 3.
2. Результатом работы алгоритма является
значение коэффициента
полинома. Затем конец алгоритма.
3. Для каждого коэффициента полинома повторять шаг 4. Затем конец
алгоритма.
4. Вычислить значение полинома при заданном значении переменной.
Схема алгоритма представлена на рисунке 28.
Рисунок 28 – Схема алгоритма вычисления значения полинома при заданном
значении переменной
Алгоритм формирования строкового представления полинома:
1. Если полином сдвигнут по оси OX, то переход к шагу
2, иначе переход
к шагу 6.
2. Записать открывающую круглую скобку перед переменной.
3. Если сдвиг отрицательный, то переход к шагу 4, иначе переход к шагу 5.
4. Записать величину сдвига со знаком «минус». Затем переход к шагу 6.
5. Записать величину сдвига со знаком «плюс».
6. Запись закрывающей круглой скобки. Затем переход к шагу 8.
44
7. Записать переменную без открывающей круглой скобки.
8. Для каждого коэффициента полинма повторять шаги 9 – 16. Затем
переход к шагу 17.
9. Если коэффициент равен нулю, то переход к шагу 8. Иначе переход к
шагу 10.
10. Если строковое представление полннома не сформировано, то переход к
шагу 14, иначе переход к шагу 11.
11. Если коэффициент меньше нуля, то переход к шагу 12, иначе переход
кшагу 13.
12. Записать величину коэффициента со знаком «плюс». Затем переход к
шагу 14.
13. Записать величину коэффициента со знаком «минус».
14. Записать знак умножения перед переменной.
15. Если степень переменной больше единицы, то переход к шагу 16, иначе
переход к шагу 8.
16. Записать после переменной знак возведения в степень и саму степень.
17. Вычислить величину сдвига полинома по оси OY.
18. Если полином сдвинут по оси OY, то переход к шагу 19, иначе переход к
шагу 24.
19. Если строковое представление полннома не сформировано, то переход к
шагу 23, иначе переход к шагу 20.
20. Если сдвиг по оси OY отрицательный, то переход к шагу 21, иначе
переход к шагу 22.
21. Записать знак «плюс». Затем переход к шагу 23.
22. Записать знак «минус».
23. Записать величину сдвига по оси OY. Затем конец алгоритма.
24. Если строковое представление полннома не сформировано, то переход к
шагу 25, иначе конец алгоритма.
25. Записать число «0».
Схема алгоритма представлена на рисунке 29.
45
Рисунок 29 – Схема алгоритма формирования строкового представления
полинома, лист 1
46
Рисунок 29, лист 2
Алгоритм вычисления полинома на заданном интервале:
1. Вычислить количество рассчитываемых точек полинома.
2. Пока значение переменной находится в пределах интервала, повторять
шаги 3 – 4. Затем конец алгоритма.
3. Вычислить значение полинома при заданном значении переменной.
4. Вычислить новое значение переменной.
Схема алгоритма приведена на рисунке 30.
Алгоритм сдвига полинома по осям OX или OY относительно начала
координат:
1. Для каждой точки полинома повторять шаги 2 – 3. Затем конец
алгоритма.
2. Вычислить свдиг точки по оси OX.
2. Вычислить сдвиг точки по оси OY.
47
Схема алгоритма представлена на рисунке 31.
Рисунок 30 – Схема алгоритма вычисления полинома на заданном интервале
Рисунок 31 – Схема алгоритма сдвига полинома
48
Алгоритм поворота полинома на произвольный угол:
1. Перевести градусы в радианы.
2. Для каждой точки полинома повторять шаги 3 – 4. Затем конец
алгоритма.
3. Вычислить новую координату x точки после поворота.
4. Вычислить новую координату y точки после поворота.
Схема алгоритма представлена на рисунке 32.
Рисунок 32 – Схема алгоритма поворота полинома
На рисунке 33 представлена общая схема формирования полинома и
отображения его графика. Сформированный пользователем список коэффицентов
полинома передается из главного окна подсистемы пользовательского интерфейса
в модуль формирования полинома подсистемы полинома, в котором н
формируется и рассчитывается. Затем табличное представление полинома
передается обратно в главное окно для отображения графика. Также на основе
списка коэффициентов формируется строковое представление полинома, которое
также передается в главное окно, но для отображениия в истории изменений
полинома.
49
Рисунок 33 – Общая схема формирования и отображения полинома, лист 1
50
Рисунок 33, лист 2
3.3.4 Файловая подсистема
Подсистема
работы
с
файлами
осуществляет
сохранение
данных,
полученных в результате работы программы, в файл, загрузку их из файла в
систему, и также создание нового файла.
Алгоритм сохранения данных в файл:
1. Если файл с указанным пользователем именем существует, то переход к
шагу 2, иначе переход к шагу 3.
2. Открыть файл на запись. Затем переход к шагу 4.
3. Создать файл.
51
4. Записать результаты работы в программе в файл.
Схема алгоритма приведена на рисунке 34.
Рисунок 34 – Схема алгоритма сохранения данных в файл
Алгоритм загрузки данных из файла:
1. Открыть файл на чтение.
2. Получить данные из файла.
Схема алгоритма приведена на рисунке 35.
Рисунок 35 – Схема алгоритма загрузки данных из файла
52
3.4 Проектирование структур данных
Основные структуры данных программы формирования полиномов для
воспроизведения удобно описывать с помощью диаграммы классов. Она
позволяет рассмотреть общий вид и взаимосвязи таких структур данных как
классы.
Анализ предметной области позволил сформировать общее представление о
классах, реализующих функционал программы, и их взаимодействии. Диаграмма
классов представлена на рисунке 36. В верхней её части показаны основные типы
данных,
используемые
в
программе
формирования
полиномов
для
воспроизведения функций действительного переменного, в нижней – классы
системы и взаимодействие между ними.
Между классами «Абстрактное синтаксическое дерево» и «Операции над
функцией», а также «Полином» и «Операции над полиномом» определены
взаимосвязи зависимости. Это означает, что изменение спецификации класса
может повлиять на работу зависимых классов.
Между классом «Главное окно» и классами «Абстрактное синтаксическое
дерево», «Полином», «Файл», «Операции над полиномом» и «Операции над
функцией» определены взаимосвязи композиции. Это означает, что время
существования содержащихся классов зависит от времени существования
содержащего их класса: если контейнер будет уничтожен, то также будет
уничтожено и все его содержимое.
Перечисляемый тип данных «Тип узла дерева» хранит информацию о
категориях, на которые подразделяются все узлы абстрактного синтаксического
дерева функции. Он включает в себя категории вещественного числа,
переменной, арифметической операции и функции, применяемой к аргументу.
Тип данных «Узел дерева» хранит информацию о типе узла, вещественное
число, а также ссылки на левое и правое поддерево дерева функции.
Тип данных «Точка» позволяет хранить координаты «x» и «y» одной точки
функции или полинома.
53
Рисунок 36 – Диаграмма классов и некоторые типы данных программы
3.5 Проектирование интерфейса
Графический
пользовательский
интерфейс
обеспечивает
удобное
взаимодействие пользователя с программой. Интерфейс пользователя включает в
себя:
1. Меню работы с файлом, а также справочное окно.
2. Поля установки интервала вычисления функции и построения ее графика.
3. Поле для ввода функции.
54
4. Кнопки для осуществления преобразований графика функции, а также
поля для изменения величин преобразований.
5. Поля установки интервала для полинома.
6. Поле ввода степени полинома и список его коэффициентов.
7. Кнопки для осуществления преобразований графика полинома.
8. Поле, на котором отображаются график исходной функции, полинома и
функции ошибки.
9. Историю изменений полинома.
Логику взаимодействия пользователя с системой удобно описывать с
использованием транзитивной сети – направленного графа, в котором вершины –
это состояния системы, а дуги – переходы между этими состояниями.
Организация логики диалога инструментария программы с пользователем
представлена на рисунке 37.
В процессе работы программа переходит в следующие состояния:
1. S0 – состояние главного окна программы, при котором основные поля
инициализированы, но функция и полином отсутствуют. Это стартовое состояние,
в котором программа находится при запуске.
2. S1 – состояние главного окна программы, при котором введена функция,
а также отображен ее график.
3. S2 – состояние главного окна программы, при котором введена функция,
сформирован полином, а также отображены их графики.
Транзитивная сеть имеет следующие подсети:
1. Преобразования функции. Включает в себя операции сдвига функции по
осям OX и OY относительно начала координат, а также поворот на произвольный
угол.
2. Преобразования полинома. Включает в себя операции вращения и сдвига
полинома.
3. Выход из программы. Включает в себя сохранение результатов перед
завершением работы в программе и собственно выход из нее.
55
Рисунок 37 – Транзитивная сеть организации логики диалога с пользователем
Подсеть «Выход из программы» имеет следующие состояния:
1. S0 – состояние главного окна программы, при котором открыто
диалоговое окно с предложением сохранить файл. Это стартовое состояние
подсети.
2. S1 – состояние главного окна программы, при котором закрыто окно
файла, но открыто диалоговое окно выхода из программы.
Транзитивная сеть подсети «Выход из программы» представлена на рисунке
38.
56
Рисунок 38 – Транзитивная сеть подсети «Выход из программы»
3.6 Реализация программы
3.6.1 Подсистема пользовательского интерфейса
Функционал главного окна описан в классе «TWindowMain». В нем
определены элементы пользовательского интерфейса программы, а также
алгоритмы их обработки и взаимодействия с пользователем.
При запуске программы вызывается метод «FormShow», в котором
осуществляется инициализация параметров графических элементов, таких как
размер и расположение на главном окне, и классов подсистем системы
формирования полиномов для воспроизведения функций действительного
переменного. Данный метод устанавливает количество столбцов и их ширину для
таблиц «GridPolyCoeffs» и «GridPolyHistory», отвечающих за отображение
коэффициентов полинома и истории изменения полинмоа соответственно. Далее
создаются экземпляры классов «TTree», «TFunc», «TPoly», «TPolyeFunc» и
«TFile», в которых реализован функционал программы формирования полиномов
для воспроизведения функций действительного переменного. Также метод
настраивает интерпретатор математических выражений, вызывая процедуру
«yymemoinit».
57
Метод «FormCloseQuery» класса «TWindowMain» отвечает за отображение
при закрытии программы диалоговых окон, вызывая стандартную функцию
«MessageDlg». Первое окно предлагает сохранить результаты работы в программе
в файл. Если пользвователь нажимает «Да» на диалогово окне, вызывается метод
«MenuFileSaveClick», имитирующий выбор пользователем пункта меню «Файл ->
Сохранить». Второе окно уточняет, действительно ли пользователь желает
закрыть программу. В таком случае метод вызывает стандартную процедуру
«Halt», которая прерывает выполнение программы.
Метод
«MenuFileCreateClick»
класса
производит
«TWindowMain»
инициализацию полей главного окна стандартными значениями и устанавливает
имя нового файла. Данный метод перед созданием нового окна вызывает
диалоговое окно, предлагающее пользователю сохранить предыдущие результаты
работы в программе в файл. Это окно реализовано аналогично окну метода
«FormCloseQuery».
Затем
метод
заполняет
поля
функции
и
полинома
стандартными значениями, устанавливает маркер нового файла и снимает маркер
сохраненного файла. Имя нового файла отображается в верхней панели
программы после ее названия.
Метод «MenuFileOpenClick» класса «TWindowMain» производит загрузку
данных из файла в программу и инициализацию полей главного кона этими
данными. Данный метод перед открытиыем файла вызывает диалоговое окно,
предлагающее пользователю сохранить предыдущие результаты работы в
программе в файл. Затем производится инициализация полей программы
значениями, полученными из файла. После этого метод вызывает процедуры
«EvalFunc», «DrawFunc», «EvalPoly» и «DrawPoly» для вычисления функции и
полинома, а также отображения их графиков. Затем метод устанавливает маркер
сохраненного файла и снимает маркер нового файла. Имя открытого файла
отображается в верхней панели программы после ее названия.
Метод «MenuFileSaveClick» класса «TWindowMain» производит сохранение
результатов работы в программе в файл. Данный метод формирует запись типа
«TFuncParams», записывая в ее поля данные об интервале, на котором определена
58
функция, а также величины сдвига и поворота функции и полинома. Затем
формируется запись типа «TFuncPolyData», которая включает в себя текстовое
представление функции, список коэффициентов полинома, а также список
величит изменений коэффициентов полинома. Далее метод устанавливает маркер
сохраненного файла и снимает маркер нового файла. Имя сохраненного файла
отображается в верхней панели программы после ее названия.
Окно «О программе» отображает название программы, версию системы, ее
автора, а также краткое описание предназначения программы. Функционал этого
окна описан в классе «TWindowAbout» и реализован в его методе «FormShow».
который хранит и записывает в поля справочного окна указанные выше данные.
Исходный код классов представлен в приложении А.
3.6.2 Подсистема исходной функции
Подсистема работы с функцией включает в себя наибольшее количество
классов и модулей структур данных. Она состоит из модулей, отвечающих за
интерпретацию текстового представления функции и классов, реализующих
работу с функцией: ее расчет при заданном значении переменной, а также сдвиг
по осям OX и OY относительно начала координат и поворот.
Лексический анализ аппроксимируемой функции осуществляется в модуле
«LEXER».
Данный
модуль
автоматически
сгенерирован
с
помощью
специализированной программы «lex», которая для генерации лексических
анализаторов использует текстовый файл со специальной структурой. Шаблоны
требуемых токенов определяются в нем при помощи
механизма регулярных
выражений. Текст файла для программы «lex» представлен в приложении А.
Синтаксический анализ аппроксимируемой функции осуществляется в
модуле «UParser». Данный модуль автоматически сгенерирован с помощью
специализированной программы «YACC», которая для генерации синтаксических
анализаторов использует специальный текстовый файл, в котором разбираемые
последовательности
описываются
с
использованием
контекстно-свободной
грамматики. Каждому правилу грамматики ставится в соответствие набор
59
действий, которые выполнит синтаксический анализатор при достижении
правила. В программе формирования полиномов для воспроизведения функций
действительного переменного в качестве таких действий выступают методы
класса, реализующего абстрактное синтаксическое дерево [3]. Текст файла для
программы «YACC» представлен в приложении А.
Абстрактное синтаксическое дерево, генерируемое интерпретатором, а
также операции над ним реализует класс «TTree». Он содержит в себе
инструментарий, отвечающий за формирование узлов дерева, а также расчет
значения функции при заданном значении переменной по имеющемуся
абстрактному синтаксическому дереву функции.
Метод «MakeNode» класса «TTree» позволяет создать новый узел дерева.
Данный метод перегружен и реализован в двух методах, отличающихся
количеством параметров. Первый метод принимает как параметр тип узла дерева,
который описан как перечисляемый тип «TNodeType» Второй метод принимает
тип узла и вещественное число «_val». Оба метода возвращают указатель на
созданный узел.
Метод «eval» класса «TTree» позволяет вычислить значение функции при
заданном значении переменной «x», которое передается как параметр. Метод
возвращает значение функции. Непосредственно вычисление происходит во
внутренней функции «evaluate», которая принимает как параметр указатель типа
«ASTptr» на вершину абстрактного синтаксического дерева. Функция возвращает
вещественное
число
типа
результатом вычисления
«Extended»,
которое
является
промежуточным
части функции. Это число формируется в зависимости
от типа узла дерева. Процедура рекурсивно обходит дерево, спуская до узлов,
представляющих переменную и вещественные числа, которые затем становятся
аргументами функций при возврате из рекурсии.
Основные операции над функцией реализует класс «TFunc». Его поля:
1. «func» - массив «TPoints» записей «TPoint». Хранит табличное
представление функции.
2. «funcSize» - количество точек в табличном представлении функции.
60
3. «shift» - запись типа «TPoint», хранящая величины сдвига функции по
осям OX и OY.
4. «rotation» - величина поворота функции в градусах.
Методы класса «TFunc» позволяют осуществлять расчет функции при всех
значениях переменной, принадлежащих заданному интервалу, с учетом шага
изменения, а также сдвиг функции по осям OX и OY относительно начала
координат и ее поворот на заданный угол.
Возможность расчета функции реализована в методе «Calc» класса «TFunc»,
принимающем абстрактно-синтаксическое дерево функции, а также интервал, в
котором определена переменная, и шаг ее изменения. Метод заполняет массив
«func» вычисленными значениями переменной и функции.
Метод «Move» класса «TFunc» позволяет произвести сдвиг функции по
осям OX или OY. Входными параметрами являются величины сдвига по каждой
из осей, поэтому допустим сдвиг по любой из осей, либо же одновременно по
обеим.
Метод «MoveToDefault» класса «TFunc» позволяет произвести сдвиг
функции из текущего положения к началу координат. Его реализация состоит в
вызове метода «Move» с аргументами, равными суммам всех сдвигов функции,
взятым с противоположным знаком.
Метод «Rotate» класса «TFunc» позволяет произвести поворот функции на
передаваемый как аргумент угол поворота в градусах, для чего использует
матрицу поворота для каждой точки функции.
Метод «RotateToDefault» класса «TFunc» позволяет произвести поворот
функции в начальное положение. Его реализация состоит в вызове метода
«Rotate» с аргументом, равным сумме всех функции полинома, взятой с
противоположным знаком.
Методы «SetShift», «SetRotation» класса «TFunc» используются для
настройки класса функции путем присваивания внутренним переменным величин
сдвига и поворота соответственно. Методы «GetFunc», «GetShift», «GetRotation»
61
применяются для получения из класса отдельных частей данных, таких как
список точек полинома, а также суммарные величины его сдвига и поворота.
Типы данных, используемые как функцией, так и полиномом, описаны в
модуле «UData». Он содержит следукющие типы данных:
1. «TPoint» - зппись, хранящая информацию об одной точке функции или
полинома.
2. «TPoints» - массив записей типа «TPoint», описывающий табличное
представление функции и полинома.
3. «TPolynome» - массив вещественных чисел типа «Extended», хранящий
список коэффициентов полинома.
Исходный код модулей и классов представлен в приложении А.
3.6.3 Подсистема аппроксимирующего полинома
Подсистема работы с полиномом включает в себя два класса: «TPoly» для
операций создания полинома и вычисления его значения в заданной точке и
«TPolyFunc» для получения полинома в табличном виде.
Поля класса «TPoly»:
1. «polynome» - список коэффициентов полинома.
2. «polySize» - количество коэффициентов полинома.
Метод «MakePoly» класса «TPoly» позволяет инициализировать класс,
получая полином в виде списка коэффициентов при переменной. Метод
принимает список коэффициентов в строчном виде.
Метод «Eval» класса «TPoly» позволяет определить значение полинома при
заданном значении переменной. Он принимает значение переменной «x» и
возвращает значение функции.
Каждое изменение полинома фиксируется в истории изменений. Для этого
метод «ToString» класса «TPoly» переводит полином в строковое представление.
Данный метод принимает величину сдвига типа «TPoint» и возвращает строковое
представление полинома в виде y = f(x). Метод учитывает величины сдвига и
62
коэффициентов, а также их знак, и формирует удобный для восприятия полином
вида (1).
Класс «TPolyFunc» имеет методы, позволяющие осуществлять расчет
полинома при всех значениях переменной, принадлежащих заданному интервалу,
с учетом шага изменения, а также сдвиг полинома по осям OX и OY относительно
начала координат и его поворот на заданный угол.
Класс «TPolyFunc» имеет следующие поля:
1. «func» - список точек полинома. Хранит его табличное представление.
2. «funcSize» - количество точек в табличном представлении полинома.
3. «shift» - запись, величины сдвига функции по осям OX и OY.
4. «rotation» - величина поворота функции в градусах.
Возможность расчета полинома реализована в методе «Calc» класса
«TPolyFunc», принимающем список коэффициентов полинома, а также интервал,
в котором определена переменная, и шаг ее изменения. Метод заполняет массив
«func» вычисленными значениями переменной и полинома.
Метод «Move» класса «TPolyFunc» позволяет произвести сдвиг полинома
по осям OX или OY. Допустим сдвиг по одной из осей, либо же одновременно по
обеим, поскольку входными параметрами служат величины сдвига по каждой из
осей.
Метод «MoveToDefault» класса «TPolyFunc» позволяет произвести сдвиг
полинома из текущего положения к началу координат. Его реализация состоит в
вызове метода «Move» с аргументами, равными суммам всех сдвигов полинома,
взятым с противоположным знаком.
Метод «Rotate» класса «TPolyFunc» позволяет произвести вращение
полинома. Данный метод принимает как входной параметр величину поворота в
градусах. При вычислении новой координаты каждой точки метод использует
матрицу поворота.
Метод
«RotateToDefault»
класса
«TPolyFunc»
позволяет
произвести
вращение полинома в начальное положение. Его реализация состоит в вызове
63
метода «Rotate» с аргументом, равным сумме всех поворотов полинома, взятой с
противоположным знаком.
Методы «SetShift», «SetRotation» класса «TPolyFunc» используются для
настройки класса полинома путем присваивания внутренним переменным
величин сдвига и поворота соответственно. Методы «GetPoly», «GetShift»,
«GetRotation» применяются для получения из класса отдельных частей данных,
таких как список точек полинома, а также суммарные величины его сдвига и
поворота.
Исходный код классов представлен в приложении А.
3.6.4 Файловая подсистема
Подсистема
осуществляющий
работы
с
файлами
включает
в
сохранение
данных,
полученных
себя
в
класс
результате
«TFile»,
работы
программы, в файл, загрузку их из файла в систему, и также создание нового
файла. Файлы программы формирования полиномов для воспроизведения
функций действительного переменного имеют расширение «.fpd».
Класс «TFile» имеет следующие поля:
1. «f» - поле типа «TFileStream», ассоциируемое с файлом, с которым в
данный момент осуществляет работу пользователь. Позволяет осуществлять
запись блоков данных в файл и загрузку данных из файла.
2. «newFileCounter» - счетчик нового файла. Используется для генерации
имени нового файла вида «New <newFileCounter>».
3. «fileName» - поле типа «String», хранящее название текущего файла.
4. «newFile» - маркер типа «Boolean». Определяет, является ли текущий
файл новым.
5. «fileSaved» - маркер типа «Boolean». Определяет, был ли сохранен
текущий файл.
Для сохранения данных в файл используется метод «Save» класса «TFile».
Он принимает как параметры имя файла и его содержимое: функцию, полином, а
также их параметры. Данный метод вначале формирует и записывает файловый
64
заголовок – запись типа «TFileHeader», затем последовательно записывает в файл
данные функции, полинома, строковое представление функции и список
коэффициентов полинома, а также список величин изменения коэффициентов
полинома.
Метод «Load» класса «TFile» позволяет загрузить данные из файла в
систему
формирования
полиномов
для
воспроизведения
функций
действительного переменного. Он принимает название файла и возвращает
функцию, полином, а также их параметры.
Метод «New» позволяет создать новый файл. Метод не принимает
параметров и возвращает название нового файла. Имя файла также сохраняется в
поле «fileName».
Структуры данных, необходимые для работы файловой подсистемы,
описанные во вспомогательном модуле «UFileData». Он содержит следующие
структуры:
1. «TInterval» - запись, хранящая информацию об интервале: его левую и
правую границу, а также шаг изменения переменной.
2. «TFuncParams» - структура данных типа «запись»,
хранящую
информацию об интервале, в котором определены функция или полином, и о шаге
изменения величины переменной, а также величины сдвига и поворота функции и
полинома.
3. «TFuncPolyData» - запись, хранящая строковое представление функции,
список
коэффициентов
полинома,
а
также
список
величин
изменения
коэжффициентов полинома.
5. «TFileHeader» - структура данных типа «запись», содержащая служебные
параметры, необходимые для корректного сохранения данных в файл, а также
выгрузки из него, такие как количество строк в строковом представлении
функции и количество коэффициентов полинома.
Исходный код класса и модуля представлен в приложении А.
65
4 ФОРМИРОВАНИЕ ПОЛИНОМА В РАЗРАБОТАННОЙ СИСТЕМЕ
В
данном
разделе
приведена
экспериментальная
проверка
работоспособности программы и соответствия требованиям, предъявляемым к
ней.
На рисунке 39 представлено главное окно программы при запуске.
Рисунок 39 – Главное окно программы при запуске
Для осуществления полиномиальной аппроксимации необходимо задать
функцию в левом поле программы (рисунок 40).
Рисунок 40 – Ввод функции, которую необходимо аппроксимировать
66
Далее необходимо нажать клавишу «Enter», после чего в поле графиков,
расположенном в центре главного окна, появится график аппроксимируемой
функции (рисунок 41).
Рисунок 41 – График аппроксимируемой функции
При необходимости можно изменить интервал, на котором определена
функция, а также шаг изменения переменной. Данные изменения производятся в
полях, расположенных в левом верхнем углу программы (рисунок 42). При
изменении
любого
из
этих
полей
график
функции
перерисовывается в соответствии с новыми данными (рисунок 43).
автоматически
67
Рисунок 42 – Изменения интервала, на котором определена функция, и шага
изменения переменной
Рисунок 43 – График аппроксимируемой функции в новом интервале и с новым
шагом изменения переменной
Программа предоставляет возможность сдвига графика функции по осям
OX и OY относительно начала координат, та также вращения на определенный
угол α. Для осуществления сдвига необходимо нажать на одну из стрелок в левом
68
нижнем углу правого окна. Направление стрелки совпадает с направлением
сдвига графика функции (рисунок 44).
Рисунок 44 – Кнопки сдвига графика функции
При необходимости величину сдвига можно изменить в поле над стрелками
(рисунок 45).
Рисунок 45 – Измененная величина сдвига графика функции
Аналогично осуществляет вращение графика функции. Кнопки поворота
находятся справа от кнопок сдвига. Вращающиеся стрелки обозначают
направление поворота (рисунок 46).
Рисунок 46 – Кнопки поворота графика функции
При необходимости величину поворота можно изменить в поле над
стрелками (рисунок 47). Величину необходимо указывать в градусах. Программа
автоматически переведет их в радианы.
69
Рисунок 47 – Измененная величина поворота графика функции
При каждом нажатии на стрелку сдвига или поворота программа
автоматически применяет к графику функции соответствующие преобразования и
перерисовывает его (рисунок 48).
Рисунок 48 – График функции, сдвинутый на 9 единиц вправо по оси OX, на 450
единиц вверх по оси OY и повернутый на 180 градусов по часовой стрелке
Кнопки с пиктограммой в виде окружности и отходящих от нее лучей
позволяют осуществить обратные преобразования и привести функцию к
исходному виду, представленному ранее.
70
После описанных выше действий можно приступить к аппроксимации
функции. Для этого необходимо заполнить поля, находящие справа в главном
окне программы. Сначала выставляется степень полинома. Это можно сделать
вручную, вписав значение в поле, либо же с помощью кнопок изменения степени.
Далее заполняется список коэффициентов полинома. Для каждой величины
указано, коэффициентом какого члена она является (рисунок 49).
Рисунок 49 – Поле степени полинома и список его коэффициентов
Далее необходимо нажать клавишу «Enter», после чего в поле графиков,
расположенном в центре главного окна, появится график полинома (рисунок 50).
После этого автоматически рассчитывается и отображается на графике функция
ошибки, показывающая отклонение полинома от функции.
Рисунок 50 – Графики аппроксимируемой функции, аппроксимирующего
полинома и функции ошибки
71
Для полинома также имеется возможность изменения интервала, на котором
он определен, а также шага изменения переменной. Соответствующие поля
расположены в правом верхнем углу программы (рисунок 51).
Рисунок 51 – Изменения интервала, на котором определен полином, и шага
изменения переменной
Аналогично
графику
функции
график
полинома
автоматически
перерисовывается в соответствии с новыми данными (рисунок 52).
Рисунок 52 – График аппроксимирующего полинома в новом интервале и с новым
шагом изменения переменной
72
Дальнейший процесс аппроксимации функции полиномом сводится к
достижению ситуации, при которой функции ошибки стремится к оси OX, то есть
к максимальному совпадению функции и полинома. Этого можно достичь
несколькими способами.
Как и для функции, для полинома определены операции сдвига и поворота,
также
имеется
возможность
изменения
соответствующих
величин.
Инструментарий для этих действий находится в правом нижнем углу главного
окна программы (рисунок 53).
Рисунок 53 – Блоки сдвига и поворота графика полинома
Аппроксимация функции полиномом возможна также путем изменения
степени полинома, а также его коэффициентов. Величины вводятся вручную,
либо же настраиваются с помощью кнопок уменьшения и увеличения величин.
Для коэффициентов полинома при использовании кнопок имеется возможность
указания шага изменения (рисунок 54).
Рисунок 54 – Измененные степень полинома и его коэффициенты
73
При
каждом
изменении
какого-либо
коэффициента
программа
автоматически перерисовывает график полинома в соответствии с новыми
данными (рисунок 55).
Рисунок 55 – График измененного полинома
Используя указанные выше операции, можно за короткое время получить
полином, идентичный аппроксимируемой функции. Конечный вид такого
полинома представлен на рисунке 56, на котором заметно практически полное
совпадение полинома и исходной функции, а также минимальная функция
ошибки.
74
Рисунок 56 – Результат полиномиальной аппроксимации
Все изменения полинома отражаются в истории изменений, которая
находится ниже поля графиков (рисунок 57). Нижняя строка отражает последнее
внесенное изменение. В ходе работы между пунктами истории можно
переключаться,
при
этом
программа
отобразит
график
полинома,
соответствующий выбранному пункту истории. Активный в данный момент
пункт истории маркирован синим квадратом.
Результаты
работы
программы
могут
быть
сохранены
в
файл
с
расширением «.fpd». Для этого необходимо выбрать пункт меню «Файл ->
75
Сохранить» или нажать на клавиатуре сочетание клавиш «CTRL+S». После этого
откроется диалоговое окно сохранения с возможность выбрать директорию и имя
файла (рисунок 58). После сохранения полное имя файла отобразится в верхней
части окна после названия программы.
Рисунок 57 – История изменения полинома
Рисунок 58 – Диалоговое окно сохранения файла
В программе предусмотрены следующие возможности работы с файлами:
1. Создание нового файла.
2. Открытие файла.
3. Сохранение файла с расширением «.fpd».
76
4. Сохранение файла с любым другим расширением.
Эти возможности представлены соответствующими пунктами главного
меню. Также для них определены комбинации клавиш для быстрого доступа
(рисунок 59).
Рисунок 59 – Меню работы с файлами
При выборе пункта меню «Справка -> О программе» или нажатии клавиши
«F1» откроется дополнительное окно, в котором содержится краткое описание
программы, а также информация об авторе и версии (рисунок 60).
Рисунок 60 – Справочное окно программы
77
ЗАКЛЮЧЕНИЕ
В ходе выполнения выпускной квалификационной работы были изучены
объект и предмет исследования, а также решены поставленные задачи:
1. Проведен анализ предметной области, а именно:
1.1.
Рассмотрены
системы
полиномиальной
аппроксимации,
аналогичные разрабатываемой программе.
1.2.Определены требования к разрабатываемой программе.
2. Разработана программа формирования полиномов для воспроизведения
функций действительного переменного.
2.1. Разработана структура программы.
2.2. Спроектированы основные структуры данных и интерфейс
пользователя.
2.3. Реализована возможность расчета и оперативного отображения
произвольной элементарной функции или комбинации функций.
2.4.
Разработан
инструментарий,
позволяющий
проводить
оперативное преобразование функции и полинома.
2.5. Реализована возможность отслеживания изменений полинома.
3. Проведено формирование полинома для воспроизведения произвольной
функции как экспериментальная проверка работоспособности программы и
соответствия ее требованиям.
Поскольку все задачи выпускной квалификационной работы решены, цель,
состоящую в сокращении времени проведения полиномиальной аппроксимации с
пошаговым контролем всех изменений полинома, а также получении полинома
вида (1), можно считать достигнутой в полной мере.
Разработанная программа формирования полиномов для воспроизведения
функций
действительного
переменного
обеспечивает
возможность
полиномиальной аппроксимации произвольной функции. Программа позволяет
полностью контролировать процесс аппроксимации, а также наблюдать все
изменения полинома в виде его графика, а также функции вида (1).
78
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ
1. Айфичер, Э. Цифровая обработка сигналов. Практический подход [Текст]
/ Э. Айфичер, Б. Джервис. – М.: "Вильямс", 2004. – 992 с.
2. Алберг, Дж. Теория сплайнов и её приложения [Текст] / Дж. Алберг, Э.
Нильсон, Дж. Уолш. – М.: Мир, 1972. – 319 с.
3. Альфред, В. Компиляторы: принципы, технологии и инструментарий =
Compilers: Principles, Techniques, and Tools [Текст] / В.А. Ахо, М.С. Лам, Р. Сети,
Дж. Д. Ульман. – М.: Вильямс, 2008. – 1184 с.
4. Бабич, А. В. UML: Первое знакомство [Текст] / А.В. Бабич. – М.:
БИНОМ. Лаборатория знаний, 2008. – 176 с.
5. Беляев, Н.Р. Введение в теорию приближенных вычислений [Текст] / Н.
Р. Беляев, И. Танатаров. – М.: МФТИ, 2011. – 203 с.
6. Бермант, А. Ф. Тригонометрия [Текст] / А.Ф. Бермант, Л.А. Люстерник. –
М.: Физматгиз, 1960. – 177 с.
7. Бесекерский, В. А. Теория систем автоматического регулирования [Текст]
/ А.В. Бесекерский, Е. П. Попов. – М.: Наука, 1975. – 768 с.
8. Выгодский, М. Я. Справочник по элементарной математике [Текст] /
М.Я.Выгодский. – М.: Наука, 1978. – 312 с.
9. Голубев, В. В. Лекции по аналитической теории дифференциальных
уравнений [Текст] / В.В. Голубев. – М.-Л.: ГОСТЕХТЕОРИЗДАТ, 1941. – 400 с.
10. Завьялов, Ю. С., Сплайны в инженерной геометрии [Текст] / Ю.С.
Завьялов, В.А. Леус, А.В. Скороспелов. — М.: Машиностроение, 1985. – 224 с.
11. Зайцев, В. В. Элементарная математика. Повторительный курс. —
Издание третье, стереотипное [Текст] / В.В. Зайцев, В.В. Рыжков, М.И. Сканави. –
М.: Наука, 1976. – 591 с.
12.
Раков,
В.И.
Информационная
система
конструирования
полиномиальных моделей: Учебное пособие [Текст] / В.И. Раков. – Орел:
ОрелГТУ, 2006. – 64 с.
79
13. Макс, Ж. Методы и техника обработки сигналов при физических
измерениях: В 2-х томах [Текст] / Ж. Макс. – М.: Мир, 1983. – 312+256 с.
14. Тынкевич, М.А. Численные методы анализа: Учебне пособие [Текст] /
М.А. Тынкевич. – Кемерово КузГТУ, 1997. – 122 с.
15.
Фихтенгольц,
Г.
М. Курс
дифференциального
и
интегрального
исчисления, тома I, II [Текст] / Г.М. Фихтенгольц. – М.: ФИЗМАТЛИТ, 2001. –
680.с.
16. Шахмейстер, А. Х. Логарифмы. Пособие для школьников, абитуриентов
и преподавателей [Текст] / А.Х. Шахмейстер. – СПб.: МЦНМО, 2016. — 288 с.
17. Янпольский А. Р. Гиперболические функции [Текст] / А.Р. Янпольский.
– М.: Физматгиз, 1960. – 195 с.
80
ПРИЛОЖЕНИЕ А
(обязательное)
ЛИСТИНГ ПРОГРАММЫ
Файл UMain.pas
unit UMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Math,
StdCtrls, ExtCtrls, TeeProcs, TeEngine, Chart, Series, TeeFunci, Buttons, Spin, Grids, ComCtrls,
Menus, UAbout, UData, LexLib, YaccLib, UParser, UAST, UFunc, UPoly, UPolyFunc, UFile,
UFileData, ImgList;
type
TWindowMain = class(TForm)
FieldFunc: TMemo; FieldService: TMemo;
ChartAllGraphics: TChart; ChartFunction: TLineSeries; ChartPolynome: TLineSeries;
ChartErrorFunc: TLineSeries; ErrorFunc: TSubtractTeeFunction;
BoxFunction: TGroupBox; BoxFuncShift: TGroupBox; BoxFuncRotation: TGroupBox;
BoxFuncInterval: TGroupBox; BoxPolynome: TGroupBox; BoxPolyBoxCoeffs: TGroupBox;
BoxPolyShift: TGroupBox; BoxPolyRotation: TGroupBox; BoxPolyInterval: TGroupBox;
FuncShiftTextValue: TEdit; FuncRotationTextValue: TEdit; FuncIntervalTextFrom: TEdit;
FuncIntervalTextTo: TEdit; FuncIntervalTextStep: TEdit;
PolyTextPower: TEdit; PolyShiftTextValue: TEdit; PolyRotationTextValue: TEdit;
PolyIntervalTextFrom: TEdit; PolyIntervalTextTo: TEdit; PolyIntervalTextStep: TEdit;
GridPolyCoeffs: TStringGrid; FuncIntervalLabelFrom: TLabel;
FuncIntervalLabelTo: TLabel; FuncIntervalLabelStep: TLabel;
PolyLabelPower: TLabel; PolyIntervalLabelFrom: TLabel; PolyIntervalLabelTo: TLabel;
PolyIntervalLabelStep: TLabel;
FuncShiftBtnLeftUp: TSpeedButton; FuncShiftBtnUp: TSpeedButton;
FuncShiftBtnRightUp: TSpeedButton; FuncShiftBtnLeft: TSpeedButton;
FuncShiftBtnDefault: TSpeedButton; FuncShiftBtnRight: TSpeedButton;
FuncShiftBtnLeftDown: TSpeedButton; FuncShiftBtnDown: TSpeedButton;
FuncShiftBtnRightDown: TSpeedButton; FuncRotationBtnLeft: TSpeedButton;
FuncRotationBtnDefault: TSpeedButton; FuncRotationBtnRight: TSpeedButton;
FuncIntervalLabelSemicolon: TLabel;
PolyShiftBtnLeftUp: TSpeedButton; PolyShiftBtnUp: TSpeedButton;
PolyShiftBtnRightUp: TSpeedButton; PolyShiftBtnLeft: TSpeedButton;
PolyShiftBtnDefault: TSpeedButton; PolyShiftBtnRight: TSpeedButton;
PolyShiftBtnLeftDown: TSpeedButton; PolyShiftBtnDown: TSpeedButton;
PolyShiftBtnRightDown: TSpeedButton; PolyRotationBtnLeft: TSpeedButton;
PolyRotationBtnDefault: TSpeedButton; PolyRotationBtnRight: TSpeedButton;
PolyIntervalLabelSemicolon: TLabel;
MainMenu: TMainMenu; MenuFile: TMenuItem; MenuFileCreate: TMenuItem;
MenuFileOpen: TMenuItem; MenuFileSave: TMenuItem; MenuFileSaveAs: TMenuItem;
MenuFileLine1: TMenuItem; MenuFileExit: TMenuItem; MenuHelp: TMenuItem;
MenuHelpAbout: TMenuItem;
DlgFileOpen: TOpenDialog; DlgFileSave: TSaveDialog;
81
UpDownPolyPower: TSpinButton; StatusBar: TStatusBar; BoxPolyHistory: TGroupBox;
GridPolyHistory: TStringGrid;
procedure FormShow(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FieldFuncKeyPress(Sender: TObject; var Key: Char);
procedure FieldFuncChange(Sender: TObject);
procedure FuncShiftTextValueChange(Sender: TObject);
procedure FuncRotationTextValueChange(Sender: TObject);
procedure FuncIntervalTextFromChange(Sender: TObject);
procedure FuncIntervalTextFromExit(Sender: TObject);
procedure FuncIntervalTextToChange(Sender: TObject);
procedure FuncIntervalTextStepChange(Sender: TObject);
procedure PolyTextPowerChange(Sender: TObject);
procedure PolyTextPowerKeyPress(Sender: TObject; var Key: Char);
procedure PolyShiftTextValueChange(Sender: TObject);
procedure PolyRotationTextValueChange(Sender: TObject);
procedure PolyIntervalTextFromChange(Sender: TObject);
procedure PolyIntervalTextFromExit(Sender: TObject);
procedure PolyIntervalTextToChange(Sender: TObject);
procedure PolyIntervalTextStepChange(Sender: TObject);
procedure GridPolyCoeffsKeyPress(Sender: TObject; var Key: Char);
procedure GridPolyHistoryKeyPress(Sender: TObject; var Key: Char);
procedure FuncShiftBtnLeftUpClick(Sender: TObject);
procedure FuncShiftBtnUpClick(Sender: TObject);
procedure FuncShiftBtnRightUpClick(Sender: TObject);
procedure FuncShiftBtnLeftClick(Sender: TObject);
procedure FuncShiftBtnDefaultClick(Sender: TObject);
procedure FuncShiftBtnRightClick(Sender: TObject);
procedure FuncShiftBtnLeftDownClick(Sender: TObject);
procedure FuncShiftBtnDownClick(Sender: TObject);
procedure FuncShiftBtnRightDownClick(Sender: TObject);
procedure FuncRotationBtnLeftClick(Sender: TObject);
procedure FuncRotationBtnDefaultClick(Sender: TObject);
procedure FuncRotationBtnRightClick(Sender: TObject);
procedure PolyShiftBtnLeftUpClick(Sender: TObject);
procedure PolyShiftBtnUpClick(Sender: TObject);
procedure PolyShiftBtnRightUpClick(Sender: TObject);
procedure PolyShiftBtnLeftClick(Sender: TObject);
procedure PolyShiftBtnDefaultClick(Sender: TObject);
procedure PolyShiftBtnRightClick(Sender: TObject);
procedure PolyShiftBtnLeftDownClick(Sender: TObject);
procedure PolyShiftBtnDownClick(Sender: TObject);
procedure PolyShiftBtnRightDownClick(Sender: TObject);
procedure PolyRotationBtnLeftClick(Sender: TObject);
procedure PolyRotationBtnDefaultClick(Sender: TObject);
procedure PolyRotationBtnRightClick(Sender: TObject);
procedure MenuFileCreateClick(Sender: TObject);
procedure MenuFileOpenClick(Sender: TObject);
procedure MenuFileSaveClick(Sender: TObject);
procedure MenuFileSaveAsClick(Sender: TObject);
82
procedure MenuFileExitClick(Sender: TObject);
procedure MenuHelpAboutClick(Sender: TObject);
procedure UpDownPolyPowerUpClick(Sender: TObject);
procedure UpDownPolyPowerDownClick(Sender: TObject);
procedure PolySpinButtonUpClick(Sender: TObject);
procedure PolySpinButtonDownClick(Sender: TObject);
procedure PolyHistoryButtonClick(Sender: TObject);
private
func: TFunc; tree: TTree; poly: TPoly; polyFunc: TPolyFunc;
polySpinBtns: array of TSpinButton; polyHistoryBtns: array of TImage;
checkedHistoryItem: Integer; R: TRect; maxInterval: TPoint; f: TFile;
procedure DrawChart(var chart: TLineSeries; func: TPoints; a, b: Extended);
procedure EvalFunc();
procedure DrawFunc();
procedure EvalPoly(pFunc: TPolyFunc);
procedure DrawPoly(pFunc: TPolyFunc);
function PolyCoeffsSetted(): Boolean;
procedure AddSpinButton(row: Integer);
procedure DeleteSpinButton();
procedure AddHistory();
procedure AddHistoryButton(row: Integer);
procedure MarkFileAsUnsaved();
function StrToReal(floatNumber: string): Extended;
function GetRange(number: string): Integer;
end;
var WindowMain: TWindowMain;
implementation
{$R *.dfm}
procedure TWindowMain.FormShow(Sender: TObject);
begin
FieldFunc.Clear; FieldService.Clear; FieldService.Hide;
ChartFunction.XValues.Order := loNone; ChartPolynome.XValues.Order := loNone;
ChartErrorFunc.XValues.Order := loNone;
StatusBar.Panels[0].Text := 'Программа: ' + Application.ExeName;
GridPolyCoeffs.ColCount := 4; GridPolyCoeffs.ColWidths[0] := 40;
GridPolyCoeffs.ColWidths[1] := 125; GridPolyCoeffs.ColWidths[2] := 21;
GridPolyCoeffs.ColWidths[3] := 70; GridPolyCoeffs.RowCount := 1;
GridPolyCoeffs.Cells[0,0] := ' c'; GridPolyCoeffs.Cells[3,0] := '0,1';
AddSpinButton(0);
GridPolyHistory.ColCount := 3; GridPolyHistory.RowCount := 2;
GridPolyHistory.FixedRows := 1; GridPolyHistory.Cells[1, 0] := 'Время';
GridPolyHistory.Cells[2, 0] := 'Полином'; GridPolyHistory.ColWidths[0] := 24;
GridPolyHistory.ColWidths[1] := 50; GridPolyHistory.ColWidths[2] := 536;
GridPolyHistory.Options := GridPolyCoeffs.Options - [goEditing];
maxInterval.x := 0; maxInterval.y := 0; checkedHistoryItem := -1;
SetLength(polyHistoryBtns, 1); WindowMain.Text := programName;
tree := TTree.Create();func := TFunc.Create();poly := TPoly.Create();
polyFunc := TPolyFunc.Create();f := TFile.Create(); f.fileSaved := True;
MenuFileCreateClick(Sender);
83
yymemoinit(FieldFunc,FieldService,FieldService,FieldService);
yyclear; yylineno := 0;
end;
procedure TWindowMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var choice: Integer;
begin
if (not f.fileSaved or f.newFile) then begin
choice := MessageDlg('Сохранить файл "' + f.fileName + '"?', mtConfirmation, [mbYes, mbNo],
0);
if (choice = mrYes) then MenuFileSaveClick(Sender);
end;
choice := MessageDlg('Вы действительно хотите выйти?', mtConfirmation, [mbYes, mbNo], 0);
if (choice = mrNo) then CanClose := False else Halt;
end;
procedure TWindowMain.FieldFuncKeyPress(Sender: TObject; var Key: Char);
const VK_ENTER = #13;
begin
if ((GetKeyState(VK_SHIFT) < 0) and (GetKeyState(VK_RETURN) < 0)) then
Key := VK_ENTER
else if (Key = VK_ENTER) then begin
EvalFunc();DrawFunc();Key := #0;
end;
end;
procedure TWindowMain.FieldFuncChange(Sender: TObject);
begin MarkFileAsUnsaved(); end;
procedure TWindowMain.FuncShiftTextValueChange(Sender: TObject);
begin MarkFileAsUnsaved(); end;
procedure TWindowMain.FuncRotationTextValueChange(Sender: TObject);
begin MarkFileAsUnsaved(); end;
procedure TWindowMain.FuncIntervalTextFromChange(Sender: TObject);
begin MarkFileAsUnsaved(); end;
procedure TWindowMain.FuncIntervalTextFromExit(Sender: TObject);
var tmp: TCaption;
begin
if ((FuncIntervalTextFrom.Text <> '') and (FuncIntervalTextTo.Text <> '')
and (FuncIntervalTextStep.Text <> '')
and (StrToReal(FuncIntervalTextFrom.Text) > StrToReal(FuncIntervalTextTo.Text))) then
begin
tmp := FuncIntervalTextFrom.Text; FuncIntervalTextFrom.Text := FuncIntervalTextTo.Text;
FuncIntervalTextTo.Text := tmp;
end;
if (FieldFunc.Text <> '') then begin
EvalFunc();DrawFunc();
end;
84
end;
procedure TWindowMain.FuncIntervalTextToChange(Sender: TObject);
begin MarkFileAsUnsaved(); end;
procedure TWindowMain.FuncIntervalTextStepChange(Sender: TObject);
begin MarkFileAsUnsaved(); end;
procedure TWindowMain.PolyTextPowerChange(Sender: TObject);
var i: Integer;
begin
with GridPolyCoeffs do begin
if (PolyTextPower.Text <> '') then RowCount := StrToInt(PolyTextPower.Text) + 1
else RowCount := 1;
if (RowCount >= 1) then Cells[0, 0] := ' c';
if (RowCount >= 2) then begin
Cells[0, 1] := ' x';
for i := 2 to (RowCount - 1) do Cells[0, i] := ' x^' + IntToStr(i);
end;
end;
MarkFileAsUnsaved();
end;
procedure TWindowMain.PolyTextPowerKeyPress(Sender: TObject; var Key: Char);
begin if not (Key in ['0'..'9', #8]) then Key := #0; end;
procedure TWindowMain.PolyShiftTextValueChange(Sender: TObject);
begin MarkFileAsUnsaved(); end;
procedure TWindowMain.PolyRotationTextValueChange(Sender: TObject);
begin MarkFileAsUnsaved(); end;
procedure TWindowMain.PolyIntervalTextFromChange(Sender: TObject);
begin MarkFileAsUnsaved(); end;
procedure TWindowMain.PolyIntervalTextFromExit(Sender: TObject);
var tmp: TCaption;
begin
if ((PolyIntervalTextFrom.Text <> '') and (PolyIntervalTextTo.Text <> '')
and (PolyIntervalTextStep.Text <> '')
and (StrToReal(PolyIntervalTextFrom.Text) > StrToReal(PolyIntervalTextTo.Text))) then
begin
tmp := PolyIntervalTextFrom.Text; PolyIntervalTextFrom.Text := PolyIntervalTextTo.Text;
PolyIntervalTextTo.Text := tmp;
end;
EvalPoly(polyFunc); DrawPoly(polyFunc);
end;
procedure TWindowMain.PolyIntervalTextToChange(Sender: TObject);
begin MarkFileAsUnsaved(); end;
procedure TWindowMain.PolyIntervalTextStepChange(Sender: TObject);
85
begin MarkFileAsUnsaved(); end;
procedure TWindowMain.GridPolyCoeffsKeyPress(Sender: TObject; var Key: Char);
const VK_ENTER = #13;
begin
if (Key = VK_ENTER) then begin
if (PolyCoeffsSetted()) then begin
EvalPoly(polyFunc); DrawPoly(polyFunc); AddHistory();
end;
Key := #0;
end;
end;
procedure TWindowMain.GridPolyHistoryKeyPress(Sender: TObject; var Key: Char);
begin MarkFileAsUnsaved(); end;
procedure TWindowMain.FuncShiftBtnLeftUpClick(Sender: TObject);
var d: Extended;
begin
if (FuncShiftTextValue.Text <> '') then begin
d := StrToReal(FuncShiftTextValue.Text); func.Move(-d, d); DrawFunc();
end;
end;
procedure TWindowMain.FuncShiftBtnUpClick(Sender: TObject);
begin
if (FuncShiftTextValue.Text <> '') then begin
func.Move(0, StrToReal(FuncShiftTextValue.Text)); DrawFunc();
end;
end;
procedure TWindowMain.FuncShiftBtnRightUpClick(Sender: TObject);
var d: Extended;
begin
if (FuncShiftTextValue.Text <> '') then begin
d := StrToReal(FuncShiftTextValue.Text); func.Move(d, d); DrawFunc();
end;
end;
procedure TWindowMain.FuncShiftBtnLeftClick(Sender: TObject);
begin
if (FuncShiftTextValue.Text <> '') then begin
func.Move(-StrToReal(FuncShiftTextValue.Text),0); DrawFunc();
end;
end;
procedure TWindowMain.FuncShiftBtnDefaultClick(Sender: TObject);
begin
if (FuncShiftTextValue.Text <> '') then begin
func.MoveToDefault();DrawFunc();
end;
end;
86
procedure TWindowMain.FuncShiftBtnRightClick(Sender: TObject);
begin
if (FuncShiftTextValue.Text <> '') then begin
func.Move(StrToReal(FuncShiftTextValue.Text), 0); DrawFunc();
end;
end;
procedure TWindowMain.FuncShiftBtnLeftDownClick(Sender: TObject);
var d: Extended;
begin
if (FuncShiftTextValue.Text <> '') then begin
d := StrToReal(FuncShiftTextValue.Text); func.Move(-d, -d); DrawFunc();
end;
end;
procedure TWindowMain.FuncShiftBtnDownClick(Sender: TObject);
begin
if (FuncShiftTextValue.Text <> '') then begin
func.Move(0, -StrToReal(FuncShiftTextValue.Text)); DrawFunc();
end;
end;
procedure TWindowMain.FuncShiftBtnRightDownClick(Sender: TObject);
var d: Extended;
begin
if (FuncShiftTextValue.Text <> '') then begin
d := StrToReal(FuncShiftTextValue.Text); func.Move(d, -d); DrawFunc();
end;
end;
procedure TWindowMain.FuncRotationBtnLeftClick(Sender: TObject);
begin
if (FuncRotationTextValue.Text <> '') then begin
func.Rotate(StrToInt(FuncRotationTextValue.Text)); DrawFunc();
end;
end;
procedure TWindowMain.FuncRotationBtnDefaultClick(Sender: TObject);
begin
if (FuncRotationTextValue.Text <> '') then begin
func.RotateToDefault();DrawFunc();
end;
end;
procedure TWindowMain.FuncRotationBtnRightClick(Sender: TObject);
begin
if (FuncRotationTextValue.Text <> '') then begin
func.Rotate(-StrToInt(FuncRotationTextValue.Text)); DrawFunc();
end;
end;
87
procedure TWindowMain.PolyShiftBtnLeftUpClick(Sender: TObject);
var d: Extended;
begin
if (PolyShiftTextValue.Text <> '') then begin
d := StrToReal(PolyShiftTextValue.Text); polyFunc.Move(-d, d); DrawPoly(polyFunc);
AddHistory();
end;
end;
procedure TWindowMain.PolyShiftBtnUpClick(Sender: TObject);
begin
if (PolyShiftTextValue.Text <> '') then begin
polyFunc.Move(0, StrToReal(PolyShiftTextValue.Text)); DrawPoly(polyFunc);
AddHistory();
end;
end;
procedure TWindowMain.PolyShiftBtnRightUpClick(Sender: TObject);
var d: Extended;
begin
if (PolyShiftTextValue.Text <> '') then begin
d := StrToReal(PolyShiftTextValue.Text); polyFunc.Move(d, d); DrawPoly(polyFunc);
AddHistory();
end;
end;
procedure TWindowMain.PolyShiftBtnLeftClick(Sender: TObject);
begin
if (PolyShiftTextValue.Text <> '') then begin
polyFunc.Move(-StrToReal(PolyShiftTextValue.Text), 0); DrawPoly(polyFunc);
AddHistory();
end;
end;
procedure TWindowMain.PolyShiftBtnDefaultClick(Sender: TObject);
begin
if (PolyShiftTextValue.Text <> '') then begin
polyFunc.MoveToDefault();DrawPoly(polyFunc); AddHistory();
end;
end;
procedure TWindowMain.PolyShiftBtnRightClick(Sender: TObject);
begin
if (PolyShiftTextValue.Text <> '') then begin
polyFunc.Move(StrToReal(PolyShiftTextValue.Text), 0); DrawPoly(polyFunc);
AddHistory();
end;
end;
88
procedure TWindowMain.PolyShiftBtnLeftDownClick(Sender: TObject);
var d: Extended;
begin
if (PolyShiftTextValue.Text <> '') then begin
d := StrToReal(PolyShiftTextValue.Text); polyFunc.Move(-d, -d); DrawPoly(polyFunc);
AddHistory();
end;
end;
procedure TWindowMain.PolyShiftBtnDownClick(Sender: TObject);
begin
if (PolyShiftTextValue.Text <> '') then begin
polyFunc.Move(0, -StrToReal(PolyShiftTextValue.Text)); DrawPoly(polyFunc);
AddHistory();
end;
end;
procedure TWindowMain.PolyShiftBtnRightDownClick(Sender: TObject);
var d: Extended;
begin
if (PolyShiftTextValue.Text <> '') then begin
d := StrToReal(PolyShiftTextValue.Text); polyFunc.Move(d, -d); DrawPoly(polyFunc);
AddHistory();
end;
end;
procedure TWindowMain.PolyRotationBtnLeftClick(Sender: TObject);
begin
if (PolyRotationTextValue.Text <> '') then begin
polyFunc.Rotate(StrToInt(PolyRotationTextValue.Text)); DrawPoly(polyFunc);
end;
end;
procedure TWindowMain.PolyRotationBtnDefaultClick(Sender: TObject);
begin
if (PolyRotationTextValue.Text <> '') then begin
polyFunc.RotateToDefault();DrawPoly(polyFunc);
end;
end;
procedure TWindowMain.PolyRotationBtnRightClick(Sender: TObject);
begin
if (PolyRotationTextValue.Text <> '') then begin
polyFunc.Rotate(-StrToInt(PolyRotationTextValue.Text)); DrawPoly(polyFunc);
end;
end;
procedure TWindowMain.MenuFileCreateClick(Sender: TObject);
var i: Integer;
begin
if (not f.fileSaved) then begin
89
if (MessageDlg('Сохранить файл "' + f.fileName + '"?', mtConfirmation, [mbYes, mbNo], 0) =
mrYes) then MenuFileSaveClick(Sender) else f.fileSaved := false;
end;
FuncIntervalTextFrom.Text := '-10'; FuncIntervalTextTo.Text := '10';
FuncIntervalTextStep.Text := '0,1'; FieldFunc.Clear; FuncShiftTextValue.Text := '1';
FuncRotationTextValue.Text := '10'; ChartFunction.Clear;
SetLength(polySpinBtns, 1); SetLength(polyHistoryBtns, 1);
for i := 1 to Length(polySpinBtns) - 1 do
if (polySpinBtns[i] <> nil) then polySpinBtns[i].Destroy;
for i := 0 to Length(polyHistoryBtns) - 1 do
if (polyHistoryBtns[i] <> nil) then polyHistoryBtns[i].Destroy;
PolyIntervalTextFrom.Text := '-10'; PolyIntervalTextTo.Text := '10';
PolyIntervalTextStep.Text := '0,1'; PolyTextPower.Text := '0'; GridPolyCoeffs.RowCount := 1;
GridPolyCoeffs.Cells[1, 0] := ''; GridPolyCoeffs.Cells[3, 0] := '0,1';
PolyShiftTextValue.Text := '1'; PolyRotationTextValue.Text := '10'; ChartPolynome.Clear;
GridPolyHistory.RowCount := 2; GridPolyHistory.Cells[1, 1] := '';
GridPolyHistory.Cells[2, 1] := '';
f.fileSaved := False; f.newFile := True; MenuFileSave.Enabled := true;
WindowMain.Text := programName + ' - ' + f.New() + ' (*)';
func.MoveToDefault(); func.RotateToDefault(); polyFunc.MoveToDefault();
polyFunc.RotateToDefault(); poly.deletePoly();
end;
procedure TWindowMain.MenuFileOpenClick(Sender: TObject);
var header: TFileHeader; funcParams: TFuncParams; polyParams: TPolyParams;
funcPolyStrs: TStrings; i: Integer;
begin
if (not f.fileSaved or f.newFile) then
if (MessageDlg('Сохранить файл "' + f.fileName + '"?', mtConfirmation, [mbYes, mbNo], 0) =
mrYes) then MenuFileSaveClick(Sender);
if (DlgFileOpen.Execute) then begin
funcPolyStrs := TStringList.Create();
f.Load(DlgFileOpen.FileName, header, funcParams, polyParams, funcPolyStrs);
with funcParams do begin
FuncIntervalTextFrom.Text := FloatToStr(interval.left);
FuncIntervalTextTo.Text := FloatToStr(interval.right);
FuncIntervalTextStep.Text := FloatToStr(interval.step); func.SetShift(shift);
func.SetRotation(rotation); FuncShiftTextValue.Text := FloatToStr(shiftVal);
FuncRotationTextValue.Text := IntToStr(rotationVal);
end;
with polyParams do begin
PolyIntervalTextFrom.Text := FloatToStr(interval.left);
PolyIntervalTextTo.Text := FloatToStr(interval.right);
PolyIntervalTextStep.Text := FloatToStr(interval.step); polyFunc.SetShift(shift);
polyFunc.SetRotation(rotation); PolyShiftTextValue.Text := FloatToStr(shiftVal);
PolyRotationTextValue.Text := IntToStr(rotationVal);
end;
FieldFunc.Lines.Clear();
for i := 0 to (header.funcStringsCount - 1) do FieldFunc.Lines.Add(funcPolyStrs[i]);
PolyTextPower.Text := IntToStr(header.polyCoeffsCount - 1); GridPolyCoeffs.ColCount := 4;
GridPolyCoeffs.RowCount := header.polyCoeffsCount;
90
for i := header.funcStringsCount to (header.funcStringsCount + header.polyCoeffsCount - 1) do
begin
GridPolyCoeffs.Cells[1, i - header.funcStringsCount] := funcPolyStrs[i];
AddSpinButton(i - header.funcStringsCount);
GridPolyCoeffs.Cells[3, i - header.funcStringsCount] := funcPolyStrs[i +
header.polyCoeffsCount];
end;
EvalFunc(); DrawFunc(); EvalPoly(polyFunc); DrawPoly(polyFunc);
funcPolyStrs.Free(); funcPolyStrs := nil;
WindowMain.Text := programName + ' - ' + DlgFileOpen.FileName;
f.newFile := False; f.fileSaved := True; MenuFileSave.Enabled := False;
f.fileName := DlgFileOpen.FileName;
end;
end;
procedure TWindowMain.MenuFileSaveClick(Sender: TObject);
var funcParams: TFuncParams; polyParams: TPolyParams; funcPolyData: TFuncPolyData;
i: Integer; cancel: Boolean;
begin
DlgFileSave.FileName := f.fileName; cancel := False;
if (f.newFile) then
if (DlgFileSave.Execute) then f.fileName := DlgFileSave.FileName else cancel := True;
if (not cancel) then begin
with funcParams do begin
interval.left := StrToReal(FuncIntervalTextFrom.Text);
interval.right := StrToReal(FuncIntervalTextTo.Text);
interval.step := StrToReal(FuncIntervalTextStep.Text); shift := func.GetShift();
rotation := func.GetRotation();shiftVal := StrToReal(FuncShiftTextValue.Text);
rotationVal := StrToInt(FuncRotationTextValue.Text);
end;
with polyParams do begin
interval.left := StrToReal(PolyIntervalTextFrom.Text);
interval.right := StrToReal(PolyIntervalTextTo.Text);
interval.step := StrToReal(PolyIntervalTextStep.Text); shift := polyFunc.GetShift();
rotation := polyFunc.GetRotation(); shiftVal := StrToReal(PolyShiftTextValue.Text);
rotationVal := StrToInt(PolyRotationTextValue.Text);
end;
FieldFunc.Lines.Add(#13#10);
with GridPolyCoeffs, funcPolyData do begin
func := FieldFunc.Lines; poly := TStringList.Create();
polyCoeffsDeltas := TStringList.Create();
for i := 0 to (RowCount - 1) do begin
poly.Add(Cells[1, i]); polyCoeffsDeltas.Add(Cells[3,i]);
end;
end;
f.Save(DlgFileSave.FileName, funcParams, polyParams, funcPolyData);
FieldFunc.Lines.Delete(FieldFunc.Lines.Count - 1);
WindowMain.Text := programName + ' - ' + DlgFileSave.FileName;
f.newFile := False; f.fileSaved := True; MenuFileSave.Enabled := False;
end;
end;
91
procedure TWindowMain.MenuFileSaveAsClick(Sender: TObject);
var funcParams: TFuncParams; polyParams: TPolyParams; funcPolyData: TFuncPolyData;
i: Integer;
begin
if (DlgFileSave.Execute) then begin
with funcParams do begin
interval.left := StrToReal(FuncIntervalTextFrom.Text);
interval.right := StrToReal(FuncIntervalTextTo.Text);
interval.step := StrToReal(FuncIntervalTextStep.Text); shift := func.GetShift();
rotation := func.GetRotation();shiftVal := StrToReal(FuncShiftTextValue.Text);
rotationVal := StrToInt(FuncRotationTextValue.Text);
end;
with polyParams do begin
interval.left := StrToReal(PolyIntervalTextFrom.Text);
interval.right := StrToReal(PolyIntervalTextTo.Text);
interval.step := StrToReal(PolyIntervalTextStep.Text); shift := polyFunc.GetShift();
rotation := polyFunc.GetRotation();shiftVal := StrToReal(PolyShiftTextValue.Text);
rotationVal := StrToInt(PolyRotationTextValue.Text);
end;
FieldFunc.Lines.Add(#13#10);
with GridPolyCoeffs, funcPolyData do begin
func := FieldFunc.Lines; poly := TStringList.Create();
polyCoeffsDeltas := TStringList.Create();
for i := 0 to (RowCount - 1) do begin
poly.Add(Cells[1, i]); polyCoeffsDeltas.Add(Cells[3,i]);
end;
end;
f.Save(DlgFileSave.FileName, funcParams, polyParams, funcPolyData);
FieldFunc.Lines.Delete(FieldFunc.Lines.Count - 1);
WindowMain.Text := programName + ' - ' + DlgFileSave.FileName;
f.newFile := False; f.fileSaved := True; MenuFileSave.Enabled := False;
end;
end;
procedure TWindowMain.MenuFileExitClick(Sender: TObject);
var canClose: Boolean;
begin FormCloseQuery(Sender, canClose); end;
procedure TWindowMain.MenuHelpAboutClick(Sender: TObject);
begin
Application.CreateForm(TWindowAbout, WindowAbout);
with WindowAbout do begin
LabelHeader.Caption := programName + ' ';
LabelProgName.Caption := programName + ' - ' + description; ShowModal();
end;
end;
procedure TWindowMain.UpDownPolyPowerUpClick(Sender: TObject);
begin
with GridPolyCoeffs do begin
RowCount := RowCount + 1; PolyTextPower.Text := IntToStr(RowCount - 1);
if (RowCount = 2) then Cells[0, 1] := ' x'
92
else Cells[0, RowCount - 1] := ' x^' + IntToStr(RowCount - 1);
Cells[3, RowCount - 1] := '0,1'; AddSpinButton(RowCount - 1);
end;
MarkFileAsUnsaved();
end;
procedure TWindowMain.UpDownPolyPowerDownClick(Sender: TObject);
begin
with GridPolyCoeffs do begin
if (RowCount - 1 > 0) then Cells[0, RowCount - 1] := '';
RowCount := RowCount - 1; PolyTextPower.Text := IntToStr(RowCount - 1);
end;
DeleteSpinButton(); MarkFileAsUnsaved();
end;
procedure TWindowMain.PolySpinButtonUpClick(Sender: TObject);
var t: Integer;
begin
t := (Sender as TSpinButton).Tag;
GridPolyCoeffs.Cells[1, t] := FloatToStr(StrToReal(GridPolyCoeffs.Cells[1, t]) +
StrToReal(GridPolyCoeffs.Cells[3, t]));
EvalPoly(polyFunc); DrawPoly(polyFunc); AddHistory();
end;
procedure TWindowMain.PolySpinButtonDownClick(Sender: TObject);
var t: Integer;
begin
t := (Sender as TSpinButton).Tag;
GridPolyCoeffs.Cells[1, t] := FloatToStr(StrToReal(GridPolyCoeffs.Cells[1, t]) StrToReal(GridPolyCoeffs.Cells[3, t]));
EvalPoly(polyFunc); DrawPoly(polyFunc); AddHistory();
end;
procedure TWindowMain.PolyHistoryButtonClick(Sender: TObject);
var t: Integer;
begin
t := (Sender as TImage).Tag;
if (checkedHistoryItem <> -1) then begin
polyHistoryBtns[checkedHistoryItem].Canvas.Brush.Color := clWhite;
polyHistoryBtns[checkedHistoryItem].Canvas.FillRect(ClientRect);
end;
polyHistoryBtns[t].Canvas.Brush.Color := ChartPolynome.SeriesColor;
polyHistoryBtns[t].Canvas.FillRect(ClientRect); checkedHistoryItem := t;
EvalPoly(polyFunc); DrawPoly((GridPolyHistory.Objects[0, t] as TPolyFunc));
end;
procedure TWindowMain.DrawChart(var chart: TLineSeries; func: TPoints; a, b: Extended);
var i: Integer;
begin
chart.Clear();
for i := 0 to Length(func) - 1 do begin
if IsNan(func[i].y) then chart.AddNullXY(func[i].x, 0, '')
93
else if ((func[i].x >= a) and (func[i].x <= b)) then chart.AddXY(func[i].x, func[i].y);
end;
end;
procedure TWindowMain.EvalFunc;
var left,step,right: Extended; range: Integer;
begin
FieldFunc.Text := LowerCase(FieldFunc.Text); tree.DeleteTree();
yyclear; yylineno := 0; yyparse(tree);
left := StrToReal(FuncIntervalTextFrom.Text); right := StrToReal(FuncIntervalTextTo.Text);
step := StrToReal(FuncIntervalTextStep.Text);
range := GetRange(Trim(FuncIntervalTextStep.Text)); func.Calc(tree, left, right, step, range);
end;
procedure TWindowMain.DrawFunc;
begin
DrawChart(ChartFunction, func.GetFunc(), StrToReal(FuncIntervalTextFrom.Text),
StrToReal(FuncIntervalTextTo.Text));
if (ChartPolynome.Count <> 0) then ErrorFunc.ReCalculate();
end;
procedure TWindowMain.EvalPoly(pFunc: TPolyFunc);
var left,step,right: Extended; range: Integer;
begin
poly.makePoly(GridPolyCoeffs.Cols[1]);
left := StrToReal(PolyIntervalTextFrom.Text); right := StrToReal(PolyIntervalTextTo.Text);
step := StrToReal(PolyIntervalTextStep.Text);
range := GetRange(Trim(PolyIntervalTextStep.Text)); pFunc.Calc(poly, left, right, step, range);
end;
procedure TWindowMain.DrawPoly(pFunc: TPolyFunc);
begin
DrawChart(ChartPolynome, pFunc.GetPoly(), StrToReal(PolyIntervalTextFrom.Text),
StrToReal(PolyIntervalTextTo.Text));
if (ChartFunction.Count <> 0) then ErrorFunc.ReCalculate();
end;
function TWindowMain.PolyCoeffsSetted: Boolean;
var i: Integer;
begin
Result := True;
for i := 0 to GridPolyCoeffs.RowCount - 1 do
if (GridPolyCoeffs.Cells[1,i] = '') then begin
Result := False; Break;
end;
end;
procedure TWindowMain.AddSpinButton(row: Integer);
var l: Integer;
begin
l := Length(polySpinBtns) + 1; SetLength(polySpinBtns, l);
polySpinBtns[l - 1] := TSpinButton.Create(self); R := GridPolyCoeffs.CellRect(2, row);
94
with polySpinBtns[l - 1] do begin
Top := R.Bottom - Height + 1; Left := R.Right - Width - 1; Parent := GridPolyCoeffs;
Visible := True; Tag := row; OnUpClick := PolySpinButtonUpClick;
OnDownClick := PolySpinButtonDownClick;
end;
end;
procedure TWindowMain.DeleteSpinButton;
var l: Integer;
begin
l := Length(polySpinBtns);
if (l > 1) then begin
polySpinBtns[l - 1].Free();polySpinBtns[l - 1] := nil; SetLength(polySpinBtns, l - 1);
end;
end;
procedure TWindowMain.AddHistory;
begin
with GridPolyHistory do begin
if (Cells[2, 1] <> '') then RowCount := RowCount + 1;
Cells[1, RowCount - 1] := TimeToStr(Now());
Cells[2, RowCount - 1] := poly.ToString(polyFunc.GetShift(), polyFunc.GetRotation());
GridPolyHistory.Objects[0, RowCount - 1] := TPolyFunc.Create(polyFunc);//polyFunc;
AddHistoryButton(RowCount - 1);
end;
end;
procedure TWindowMain.AddHistoryButton(row: Integer);
var l: Integer;
begin
l := Length(polyHistoryBtns) + 1; SetLength(polyHistoryBtns, l);
polyHistoryBtns[l - 1] := TImage.Create(self); R := GridPolyHistory.CellRect(0, row);
with polyHistoryBtns[l - 1] do begin
Height := GridPolyHistory.DefaultRowHeight; Width := Height; Top := R.Top;
Left := R.Left; Parent := GridPolyHistory; Visible := True; Tag := row;
OnClick := PolyHistoryButtonClick;
end;
PolyHistoryButtonClick(polyHistoryBtns[l - 1]);
end;
procedure TWindowMain.MarkFileAsUnsaved;
begin
MenuFileSave.Enabled := true;
if (f <> nil) then begin
if (f.fileSaved) then WindowMain.Text := WindowMain.Text + ' (*)';
f.fileSaved := False;
end;
end;
function TWindowMain.StrToReal(floatNumber: string): Extended;
begin
Result := StrToFloat(StringReplace(floatNumber, '.', ',', [rfReplaceAll, rfIgnoreCase]));
95
end;
function TWindowMain.GetRange(number: string): Integer;
var commaPos: Integer;
begin
commaPos := Pos(',', number);
if (commaPos <> 0) then
Result := -Length(Copy(number, commaPos + 1, Length(number) - commaPos))
else Result := 0;
end;
end.
Файл UAbout.pas
unit UAbout;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
const
version = '1.3.2'; copyright = '©'; author = 'Kirill Dudorov'; startDate = '2017';
currentDate = '2018'; description = 'система формирования полиномов для воспроизведения
функций действительного переменного';
type
TWindowAbout = class(TForm)
ButtonOK: TButton; LabelHeader: TLabel; LabelProgName: TLabel; LabelVersion: TLabel;
LabelAuthorAndDate: TLabel;
procedure FormShow(Sender: TObject);
end;
var WindowAbout: TWindowAbout;
implementation
{$R *.dfm}
procedure TWindowAbout.FormShow(Sender: TObject);
begin
ButtonOK.ModalResult := mrOk; LabelProgName.WordWrap := True;
LabelVersion.Caption := 'Версия: ' + version;
LabelAuthorAndDate.Caption := copyright + ' ' + author + ', ' + startDate + ' - ' + currentDate;
end;
end.
Файл lexer.l
const error = -1;
D [0-9]+
%%
{D}(\,{D})?
"x"
"e"
begin yylval.yyreal := StrToFloat(yytext); returni(num); end;
returnc('x');
begin yylval.yyreal := eVal; returni(e); end;
96
"pi"
"exp"
"ln"
"lg"
"log"
"sin"
"cos"
"t"("g"|"an")
"c"("tg"|"ot")
"sec"
"c"("osec"|"sc")
"arcsin"
"arccos"
"arct"("g"|"an")
"arcc"("tg"|"ot"("an")?)
"arcsec"
"arcc"("osec"|"sc")
"s"("in")?"h"
"c"("os")?"h"
"t"("an")?"h"
"c"("o")?"th"
"sech"
"csch"
"+"
"-"
"*"
"/"
"^"
"("
")"
';'
" "|\n
.
begin yylval.yyreal := piVal; returni(pi); end;
begin yylval.yyfunc := yytext; returni(exp); end;
begin yylval.yyfunc := yytext; returni(ln); end;
begin yylval.yyfunc := yytext; returni(lg); end;
begin yylval.yyfunc := yytext; returni(log); end;
begin yylval.yyfunc := yytext; returni(sin); end;
begin yylval.yyfunc := yytext; returni(cos); end;
begin yylval.yyfunc := yytext; returni(tg); end;
begin yylval.yyfunc := yytext; returni(ctg); end;
begin yylval.yyfunc := yytext; returni(sec); end;
begin yylval.yyfunc := yytext; returni(cosec); end;
begin yylval.yyfunc := yytext; returni(arcsin); end;
begin yylval.yyfunc := yytext; returni(arccos); end;
begin yylval.yyfunc := yytext; returni(arctg); end;
begin yylval.yyfunc := yytext; returni(arcctg); end;
begin yylval.yyfunc := yytext; returni(arcsec); end;
begin yylval.yyfunc := yytext; returni(arccosec); end;
begin yylval.yyfunc := yytext; returni(sh); end;
begin yylval.yyfunc := yytext; returni(ch); end;
begin yylval.yyfunc := yytext; returni(th); end;
begin yylval.yyfunc := yytext; returni(cth); end;
begin yylval.yyfunc := yytext; returni(sech); end;
begin yylval.yyfunc := yytext; returni(csch); end;
returnc('+');
returnc('-');
returnc('*');
returnc('/');
returnc('^');
returnc('(');
returnc(')');
returnc(';');
;
returni(error);
Файл parser.y
%{
unit parser;
interface
uses Lexlib, YaccLib, ASTUnit, dialogs;
const eVal = 2.7182818284590452353602874713527;
piVal = 3.1415926535897932384626433832795;
type func = string[16];
function yyparse(tree: TTree) : Integer; forward;//
%}
%left '+' '-'
%left '*' '/'
%left uminus
%right '^'
97
%token <real> num
%token <real> e
%token <real> pi
%token <func> exp
%token <func> ln
%token <func> lg
%token <func> log
%token <func> sin
%token <func> cos
%token <func> tg
%token <func> tan
%token <func> ctg
%token <func> cot
%token <func> sec
%token <func> cosec
%token <func> csc
%token <func> arcsin
%token <func> arccos
%token <func> arctg
%token <func> arctan
%token <func> arcctg
%token <func> arccot
%token <func> arccotan
%token <func> arcsec
%token <func> arccosec
%token <func> arccsc
%token <func> sh
%token <func> sinh
%token <func> ch
%token <func> cosh
%token <func> th
%token <func> tanh
%token <func> cth
%token <func> coth
%token <func> sech
%token <func> csch
%type <ASTptr> START
%type <ASTptr> EXPR
%type <ASTptr> FUNC
%%
START: EXPR
{ tree.Head := $1; $$ := $1; }
;
EXPR: EXPR '+' EXPR
{ $$ := tree.makeNode(plus); $$^.left := $1; $$^.right := $3; }
| EXPR '-' EXPR
{ $$ := tree.makeNode(minus); $$^.left := $1; $$^.right := $3; }
| EXPR '*' EXPR
{ $$ := tree.makeNode(mult); $$^.left := $1; $$^.right := $3; }
| EXPR '/' EXPR
{ $$ := tree.makeNode(_div); $$^.left := $1; $$^.right := $3; }
| '-' EXPR %prec uminus
{ $$ := tree.makeNode(_uminus); $$^.left := $2; }
| EXPR '^' EXPR
{ $$ := tree.makeNode(pow); $$^.left := $1; $$^.right := $3; }
| '(' EXPR ')'
{$$ := $2;}
| FUNC '(' EXPR ')' { $1^.left := $3; $$ := $1; }
98
| num
| 'x'
|e
| pi
;
FUNC: exp
| ln
| lg
| sin
| cos
| tg
| tan
| ctg
| cot
| sec
| cosec
| csc
| arcsin
| arccos
| arctg
| arctan
| arcctg
| arccot
| arccotan
| arcsec
| arccosec
| arccsc
| sh
| sinh
| ch
| cosh
| th
| tanh
| cth
| coth
| sech
| csch
;
%%
{$I LEXER.PAS}
end.
{$$ := tree.makeNode(_value, $1);}
{$$ := tree.makeNode(variable);}
{$$ := tree.makeNode(_value, eVal);}
{$$ := tree.makeNode(_value, piVal);}
{$$ := tree.makeNode(_exp);}
{$$ := tree.makeNode(_ln);}
{$$ := tree.makeNode(_lg);}
{$$ := tree.makeNode(_sin);}
{$$ := tree.makeNode(_cos);}
{$$ := tree.makeNode(_tg);}
{$$ := tree.makeNode(_tg);}
{$$ := tree.makeNode(_ctg);}
{$$ := tree.makeNode(_ctg);}
{$$ := tree.makeNode(_sec);}
{$$ := tree.makeNode(_cosec);}
{$$ := tree.makeNode(_cosec);}
{$$ := tree.makeNode(_arcsin);}
{$$ := tree.makeNode(_arccos);}
{$$ := tree.makeNode(_arctg);}
{$$ := tree.makeNode(_arctg);}
{$$ := tree.makeNode(_arcctg);}
{$$ := tree.makeNode(_arcctg);}
{$$ := tree.makeNode(_arcctg);}
{$$ := tree.makeNode(_arcsec);}
{$$ := tree.makeNode(_arccosec);}
{$$ := tree.makeNode(_arccosec);}
{$$ := tree.makeNode(_sh);}
{$$ := tree.makeNode(_sh);}
{$$ := tree.makeNode(_ch);}
{$$ := tree.makeNode(_ch);}
{$$ := tree.makeNode(_th);}
{$$ := tree.makeNode(_th);}
{$$ := tree.makeNode(_cth);}
{$$ := tree.makeNode(_cth);}
{$$ := tree.makeNode(_sech);}
{$$ := tree.makeNode(_csch);}
Файл UAST.pas
unit UAST;
interface
uses SysUtils, Math;
type TNodeType = (variable, _value, plus, minus, mult, _div, _uminus, pow, _exp, _log, _ln, _lg, _sin,
_cos, _tg, _ctg, _sec, _cosec, _arcsin, _arccos, _arctg, _arcctg, _arcsec, _arccosec, _sh, _ch, _th, _cth,
_sech, _csch);
ASTptr = ^ASTnode;
99
ASTnode = record
_type: TNodeType; value: Extended; left: ASTptr; right: ASTptr;
end;
TTree = class
public
Head: ASTptr;
constructor Create;
destructor Destroy; override;
function makeNode(_type: TNodeType; _val: Extended): ASTptr; overload;
function makeNode(_type: TNodeType): ASTptr; overload;
procedure DeleteTree(node: ASTptr); overload;
procedure DeleteTree(); overload;
function eval(x: Extended): Extended;
end;
implementation
constructor TTree.Create;
begin Head := nil; end;
destructor TTree.Destroy;
begin DeleteTree(Head); Head := nil; inherited; end;
function TTree.makeNode(_type: TNodeType; _val: Extended): ASTptr;
begin
New(Result);
Result^._type := _type; Result^.value:= _val; Result^.left := nil; Result^.right := nil;
end;
function TTree.makeNode(_type: TNodeType): ASTptr;
begin Result := makeNode(_type, 0.0); end;
procedure TTree.DeleteTree(node: ASTptr);
begin
if (node <> nil) then begin
DeleteTree(node^.left); DeleteTree(node^.right); Dispose(node);
end;
end;
procedure TTree.DeleteTree;
begin DeleteTree(Head); end;
function TTree.eval(x: Extended): Extended;
function evaluate(func: ASTptr): Extended;
begin
if (func <> nil) then begin
case (func^._type) of
variable: Result := x;
_value: Result := func^.value;
plus:
Result := evaluate(func^.left) + evaluate(func^.right);
minus:
Result := evaluate(func^.left) - evaluate(func^.right);
100
mult:
_div:
Result := evaluate(func^.left) * evaluate(func^.right);
begin
try Result := evaluate(func^.left) / evaluate(func^.right);
except on E: EZeroDivide do Result := NaN;
end;
end;
_uminus: Result := -evaluate(func^.left);
pow:
begin
try Result := Power(evaluate(func^.left),evaluate(func^.right));
except on E: EInvalidOp do Result := NaN;
end;
end;
_exp:
Result := Exp(evaluate(func^.left));
_log:
Result := LogN(evaluate(func^.left), evaluate(func^.right));
_ln:
begin
try Result := Ln(evaluate(func^.left));
except on E: EZeroDivide do Result := NaN;
end;
end;
_lg:
begin
try Result := Log10(evaluate(func^.left));
except on E: EZeroDivide do Result := NaN;
end;
end;
_sin:
Result := Sin(evaluate(func^.left));
_cos:
Result := Cos(evaluate(func^.left));
_tg:
begin
try Result := Tan(evaluate(func^.left));
except Result := NaN;
end;
end;
_ctg:
begin
try Result := Cotan(evaluate(func^.left));
except on E: EZeroDivide do Result := NaN;
end;
end;
_sec:
begin
try Result := Sec(evaluate(func^.left));
except on E: EZeroDivide do Result := NaN;
end;
end;
_cosec: begin
try Result := Csc(evaluate(func^.left));
except on E: EZeroDivide do Result := NaN;
end;
end;
_arcsin: begin
try Result := ArcSin(evaluate(func^.left));
except on E: EInvalidOp do Result := NaN;
end;
end;
_arccos: begin
101
try Result := ArcCos(evaluate(func^.left));
except on E: Exception do Result := NaN;
end;
end;
_arctg: Result := ArcTan(evaluate(func^.left));
_arcctg: Result := (pi/2 - ArcTan(evaluate(func^.left)));
_arcsec: begin
try Result := ArcCos(1/evaluate(func^.left));
except on E: Exception do Result := NaN;
end;
end;
_arccosec: begin
try Result := ArcSin(1/evaluate(func^.left));
except on E: Exception do Result := NaN;
end;
end;
_sh:
Result := Sinh(evaluate(func^.left));
_ch:
begin
try Result := Cosh(evaluate(func^.left));
except on E: EZeroDivide do Result := NaN;
end;
end;
_th:
begin
try Result := Tanh(evaluate(func^.left));
except on E: EZeroDivide do Result := NaN;
end;
end;
_cth:
begin
try Result := CotH(evaluate(func^.left));
except on E: EZeroDivide do Result := NaN;
end;
end;
_sech:
begin
try Result := SecH(evaluate(func^.left));
except on E: EZeroDivide do Result := NaN;
end;
end;
_csch:
begin
try Result := CscH(evaluate(func^.left));
except on E: EZeroDivide do Result := NaN;
end;
end;
else Result := NaN;
end;
end
else Result := NaN;
end;
begin Result := evaluate(Head); end;
end.
102
Файл UFunc.pas
unit UFunc;
interface
uses Math, Dialogs, SysUtils, UAST, UData;
type
TFunc = class
private
func: TPoints; funcSize: Integer; shift: TPoint; rotation: Integer;
public
constructor Create();
procedure Calc(f:TTree; a: Extended; b: Extended; step: Extended; range: Integer);
procedure Move(dx: Extended; dy: Extended);
procedure MoveToDefault();
procedure Rotate(degree: Integer);
procedure RotateToDefault();
procedure SetShift(shift: TPoint);
procedure SetRotation(rotation: Integer);
function GetFunc(): TPoints;
function GetShift(): TPoint;
function GetRotation(): Integer;
end;
implementation
constructor TFunc.Create;
begin
funcSize := 0; shift.x := 0.0; shift.y := 0.0; rotation := 0;
end;
procedure TFunc.Calc(f:TTree; a, b, step: Extended; range: Integer);
var i, j, nn: Integer; left, right, difference: Extended; p: TPoint;
begin
range := range; funcSize := Round(RoundTo(b - a, range) / step) + 1;
SetLength(func, funcSize); left := a; right := b; i := 0; nn := 0; difference := 0;
while ((left <= right) and (i < funcSize)) do begin
p.x := left; p.y := f.eval(left);
if (not IsNan(p.y)) then Inc(nn);
if (nn = 2) then begin
j := i - 1;
while (IsNan(func[j].y) and (j > 0)) do Dec(j);
difference := p.y - func[j].y;
end
else if (nn > 2) then begin
j := i - 1;
while (IsNan(func[j].y) and (j > 0)) do Dec(j);
if (Sign(difference) <> Sign(p.y - func[j].y)) then begin
func[i].x := p.x - RoundTo(step/2, range); func[i].y := NaN; Inc(i); nn := 0; Inc(funcSize);
end;
difference := p.y - func[j].y;
end;
func[i] := p; Inc(i); left := RoundTo(left + step, range);
103
if(i = Length(func)) then SetLength(func, Length(func)*2);
end;
SetLength(func, FuncSize);
end;
procedure TFunc.Move(dx, dy: Extended);
var i: Integer;
begin
shift.x := shift.x + dx; shift.y := shift.y + dy;
for i := 0 to (funcSize - 1) do begin
func[i].x := func[i].x + dx; сfunc[i].y := func[i].y + dy;
end;
end;
procedure TFunc.MoveToDefault;
begin Move(-shift.x, -shift.y); end;
procedure TFunc.Rotate(degree: Integer);
var i: Integer; theta, sinTheta, cosTheta, x, y: Extended;
begin
rotation := rotation + degree; theta := DegToRad(degree);
sinTheta := Sin(theta); cosTheta := Cos(theta);
for i := 0 to (funcSize - 1) do
if (not IsNan(func[i].y)) then begin
x := func[i].x*cosTheta - func[i].y*sinTheta; y := func[i].x*sinTheta + func[i].y*cosTheta;
func[i].x := x; func[i].y := y;
end;
end;
procedure TFunc.RotateToDefault;
begin Rotate(-rotation); end;
procedure TFunc.SetShift(shift: TPoint);
begin Self.shift := shift; end;
procedure TFunc.SetRotation(rotation: Integer);
begin Self.rotation := rotation; end;
function TFunc.GetFunc: TPoints;
begin Result := func; end;
function TFunc.GetShift: TPoint;
begin Result := shift; end;
function TFunc.GetRotation: Integer;
begin Result := rotation; end;
end.
Файл UPoly.pas
unit UPoly;
interface
104
uses Classes, SysUtils, Math, UData;
type
TPoly = class
private
polySize: Integer;
public
polynome: TPolynome;
constructor Create();
destructor Destroy(); override;
procedure makePoly(coefs: TStrings);
procedure deletePoly();
function eval(x: Extended): Extended;
function ToString(shift: TPoint; rotation: Integer): string;
end;
implementation
constructor TPoly.Create;
begin polySize := 0; end;
destructor TPoly.Destroy;
begin deletePoly(); inherited; end;
procedure TPoly.makePoly(coefs: TStrings);
var i: Integer;
begin
polySize := coefs.Count; SetLength(polynome, polySize);
for i := 0 to (polySize - 1) do polynome[i] := StrToFloat(coefs[i]);
end;
procedure TPoly.deletePoly;
begin SetLength(polynome, 0); end;
function TPoly.eval(x: Extended): Extended;
var i: Integer;
begin
if (polySize = 1) then begin
Result := polynome[0]; Exit;
end;
Result := polynome[0] + polynome[1] * x;
for i := 2 to polySize - 1 do Result := Result + polynome[i] * Power(x, i);
end;
function TPoly.ToString(shift: TPoint; rotation: Integer): string;
var i: Integer; coeff: Extended; roundShift: TPoint; polyStr: string; xStr: string;
begin
Result := ''; roundShift := shift;
if (roundShift.x <> 0) then begin
xStr := '(x';
if (roundShift.x < 0) then xStr := xStr + ' + ' + FloatToStr(-1*roundShift.x)
else xStr := xStr + ' - ' + FloatToStr(roundShift.x);
105
xStr := xStr + ')';
end
else xStr := 'x';
for i := 1 to (polySize - 1) do begin
coeff := polynome[i];
if (coeff = 0) then Continue;
if (i <> (polySize - 1)) then begin
if (coeff < 0) then begin
polyStr := ' - '; coeff := -1*coeff;
end
else polyStr := ' + ';
end
else polyStr := '';
polyStr := polyStr + FloatToStr(coeff) + '*' + xStr;
if (i > 1) then polyStr := polyStr + '^' + FloatToStr(i);
Result := polyStr + Result;
end;
roundShift.y := roundShift.y + polynome[0];
if (roundShift.y <> 0) then begin
if (Result <> '') then begin
if (roundShift.y < 0) then begin
Result := Result + ' - '; roundShift.y := -1*roundShift.y;
end
else Result := Result + ' + ';
end;
Result := Result + FloatToStr(roundShift.y);
end
else if (Result = '') then Result := '0';
end;
end.
Файл UPolyFunc.pas
unit UPolyFunc;
interface
uses Math, UData, UPoly;
type
TPolyFunc = class
private
func: TPoints; funcSize: Integer; shift: TPoint; rotation: Integer;
public
constructor Create(); overload;
constructor Create(anotherPolyFunc: TPolyFunc); overload;
procedure Calc(f: TPoly; a: Extended; b: Extended; step: Extended; range: Integer);
procedure Move(dx: Extended; dy: Extended);
procedure MoveToDefault();
procedure Rotate(degree: Integer);
procedure RotateToDefault();
procedure SetShift(shift: TPoint);
procedure SetRotation(rotation: Integer);
106
function GetPoly(): TPoints;
function GetShift(): TPoint;
function GetRotation(): Integer;
end;
implementation
constructor TPolyFunc.Create;
begin
funcSize := 0; shift.x := 0; shift.y := 0;
end;
constructor TPolyFunc.Create(anotherPolyFunc: TPolyFunc);
begin
self.func := anotherPolyFunc.GetPoly(); self.funcSize := 0;
self.shift := anotherPolyFunc.GetShift(); self.rotation := anotherPolyFunc.GetRotation();
end;
procedure TPolyFunc.Calc(f: TPoly; a, b, step: Extended; range: Integer);
var i: Integer; left, right: Extended;
begin
funcSize := Round(RoundTo(b - a, range) / step) + 1; SetLength(func, funcSize);
left := a; right := b; i := 0;
while (left <= right) do begin
func[i].x := left; func[i].y := f.eval(left); Inc(i); left := RoundTo(left + step, range);
end;
end;
procedure TPolyFunc.Move(dx, dy: Extended);
var i: Integer;
begin
shift.x := shift.x + dx; shift.y := shift.y + dy;
for i := 0 to (funcSize - 1) do begin
func[i].x := func[i].x + dx; func[i].y := func[i].y + dy;
end;
end;
procedure TPolyFunc.MoveToDefault;
begin Move(-shift.x, -shift.y); end;
procedure TPolyFunc.Rotate(degree: Integer);
var i: Integer; theta, sinTheta, cosTheta, x, y: Extended;
begin
rotation := rotation + degree; theta := DegToRad(degree);
sinTheta := Sin(theta); cosTheta := Cos(theta);
for i := 0 to (funcSize - 1) do
if (not IsNan(func[i].y)) then begin
x := func[i].x*cosTheta - func[i].y*sinTheta; y := func[i].x*sinTheta + func[i].y*cosTheta;
func[i].x := x; func[i].y := y;
end;
end;
procedure TPolyFunc.RotateToDefault;
begin Rotate(-rotation); end;
107
procedure TPolyFunc.SetShift(shift: TPoint);
begin Self.shift := shift; end;
procedure TPolyFunc.SetRotation(rotation: Integer);
begin Self.rotation := rotation; end;
function TPolyFunc.GetPoly: TPoints;
begin Result := func; end;
function TPolyFunc.GetShift: TPoint;
begin Result := shift; end;
function TPolyFunc.GetRotation: Integer;
begin Result := rotation; end;
end.
Файл UData.pas
unit UData;
interface
uses Classes;
const programName = 'PolyMaker';
type TFuncType = (func, poly);
TPoint = record
x: Extended; y: Extended;
end;
TPoints = array of TPoint;
TPolynome = array of Extended;
implementation
end.
Файл UFile.pas
unit UFile;
interface
uses Classes, SysUtils, Dialogs, Controls, StdCtrls, UFileData;
type
TFile = class
private
f: TFileStream; newFileCounter: Integer;
public
fileName: string; newFile: Boolean; fileSaved: Boolean;
constructor Create();
function New(): string;
108
procedure Save(const fileName: string; funcParams: TFuncParams; polyParams: TPolyParams;
funcPolyData: TFuncPolyData);
procedure Load(const fileName: string; var header: TFileHeader; var funcParams: TFuncParams;
var polyParams: TPolyParams; var funcPolyStrings: TStrings);
end;
implementation
constructor TFile.Create;
begin
newFileCounter := 0; fileName := ''; fileSaved := False;
end;
function TFile.New: string;
begin
Result := newFileName + ' ' + IntToStr(newFileCounter);
fileName := Result; Inc(newFileCounter);
end;
procedure TFile.Save(const fileName: string; funcParams: TFuncParams; polyParams: TPolyParams;
funcPolyData: TFuncPolyData);
var mode: Word; header: TFileHeader;
begin
if(FileExists(fileName)) then mode := fmOpenWrite
else mode := fmCreate;
f := TFileStream.Create(fileName, mode, fmShareDenyWrite);
with header, funcPolyData do begin
funcStringsCount := func.Count; polyCoeffsCount := poly.Count;
end;
f.WriteBuffer(header, SizeOf(TFileHeader));
f.WriteBuffer(funcParams, SizeOf(TFuncParams));
f.WriteBuffer(polyParams, SizeOf(TPolyParams));
with funcPolyData do begin
func.SaveToStream(f); poly.SaveToStream(f); polyCoeffsDeltas.SaveToStream(f);
end;
f.Free(); f := nil;
end;
procedure TFile.Load(const fileName: string; var header: TFileHeader; var funcParams:
TFuncParams;
var polyParams: TPolyParams; var funcPolyStrings: TStrings);
begin
f := TFileStream.Create(fileName, fmOpenRead, fmShareDenyWrite);
f.ReadBuffer(header, SizeOf(TFileHeader));
f.ReadBuffer(funcParams, SizeOf(TFuncParams));
f.ReadBuffer(polyParams, SizeOf(TPolyParams)); funcPolyStrings.LoadFromStream(f);
f.Free(); f := nil;
end;
end.
109
Файл UFileData.pas
unit UFileData;
interface
uses Classes, SysUtils, UData;
const fileExtension = '.fpd'; newFileName = 'New';
type
TInterval = record
left: Extended; right: Extended; step: Extended;
end;
TFuncParams = record
interval: TInterval; shift: TPoint; rotation: Integer; shiftVal: Extended; rotationVal: Integer;
end;
TPolyParams = record
interval: TInterval; shift: TPoint; rotation: Integer; shiftVal: Extended; rotationVal: Integer;
end;
TFuncPolyData = record
func: TStrings; poly: TStrings; polyCoeffsDeltas: TStrings;
end;
TFileHeader = record
funcStringsCount: Integer; polyCoeffsCount: Integer;
end;
implementation
end.
111
ИНФОРМАЦИОННО-ПОИСКОВАЯ ХАРАКТЕРИСТИКА
ДОКУМЕНТА НА ЭЛЕКТРОННОМ НОСИТЕЛЕ
Наименование
группы атрибутов
атрибута
1. Описание
Обозначение документа
документа
(идентификатор(ы)
файла(ов))
Наименование документа
Класс документа
Вид документа
Аннотация
Использование
документа
2. Даты и время
3. Создатели
4. Внешние
ссылки
5. Защита
6. Характеристики
содержания
Дата и время
копирования документа
Дата создания документа
Дата утверждения
документа
Автор
Изготовитель
Ссылки на другие
документы
Санкционирование
Классификация защиты
Объем информации
документа
Характеристики документа
на электронном носителе
\Плакаты\Презентация.ppt
Демонстрационные плакаты
к выпускной
квалификационной работе
ЕСКД
Оригинал документа на
электронном носителе
Демонстрационный
материал, отображающий
основные этапы выполнения
выпускной
квалификационной работы
Операционная система
Windows 7, Microsoft
PowerPoint 2007
13.06.2018
29.05.2018
18.06.2018
Дудоров К.А.
Дудоров К.А.
Удостоверяющий лист
№ 140038
ОГУ имени И.С. Тургенева
По законодательству РФ
831488 Б
112
7. Структура
документа(ов)
Наименование плаката
(слайда) №1
Наименование плаката
(слайда) №2
Наименование плаката
(слайда) №3
Наименование плаката
(слайда) №4
Наименование плаката
(слайда) №5
Наименование плаката
(слайда) №6
Наименование плаката
(слайда) №7
Наименование плаката
(слайда) №8
Наименование плаката
(слайда) №9
Наименование плаката
(слайда) №10
Наименование плаката
(слайда) №11
Наименование плаката
(слайда) №12
Титульный лист
Актуальность работы
Цели и задачи работы
Сравнительный обзор
аналогов
Варианты использования
программы
Структура программы
Основные структуры данных
Схема конечного автомата
лексического анализатора
программы
Общая схема алгоритма
построения и отображения
полинома
Общая схема алгоритма
построения и отображения
полинома
Описание пользовательского
интерфейса
Формирование полинома в
разработанной системе
1/--страниц
Пожаловаться на содержимое документа