Автор Юрий
Писарев, дата публикации 04 апреля 2002г.
В этой статье представлена новая версия модуля для расчета
формул. Я сделал очень много нововведений, в том числе полностью изменил
структуру сценариев. В предыдущем варианте сценарий состоял примерно из равных
частей по 4 байта - не рационально, но намного проще. Полное описание структуры
новых сценариев приведено в исходном файле модуля. Изменился синтаксис формулы,
больше не нужно заключать функции в скобки. Ниже приведены все элементы
синтаксиса, многие из них также претерпели изменения:
Single: тип, обозначает вещественное 32 битное число
Double: тип, обозначает вещественное 64 битное число
Int64: тип, обозначает целое знаковое 64 битное число
Integer: тип, обозначает целое знаковое 32 битное число
Longword: тип, обозначает целое беззнаковое 32 битное
число
Smallint: тип, обозначает целое знаковое 16 битное число
Word: тип, обозначает целое беззнаковое 16 битное число
Shortint: тип, обозначает целое знаковое 8 битное число
Byte: тип, обозначает целое беззнаковое 8 битное число
if: зарезервированное слово, обозначает логическое
выражение
and: операнд, используется для связывания двух логических
выражений. Аналогично логическому and в Delphi
or: операнд, используется для связывания двух логических
выражений. Аналогично логическому or в Delphi
xor: операнд, используется для связывания двух логических
выражений. Аналогично логическому xor в Delphi
not: операнд, меняет логическое значение на
противоположное.
> логическая функция, если первое математическое
выражение больше второго, то возвращает истину, в противном случае возвращает
ложь
<: логическая функция, если первое математическое
выражение меньше второго, то возвращает истину, в противном случае возвращает
ложь
<>: логическая функция, если первое математическое
выражение не равно второму, то возвращает истину, в противном случае
возвращает ложь
=>: логическая функция, если первое математическое
выражение больше или равно второму, то возвращает истину, в противном случае
возвращает ложь
<=: логическая функция, если первое математическое
выражение меньше или равно второму, то возвращает истину, в противном случае
возвращает ложь
=: логическая функция, если первое математическое
выражение равно второму, то возвращает истину, в противном случае возвращает
ложь
Odd: логическая функция, возвращает истину если
математическое выражение нечетное
True: функция. Возвращает истину. Это величина может
принимать значение 1
False: функция. Возвращает ложь. Это величина может
принимать значение 0
+: операнд, сложение
-: операнд, вычитание
*: математическая функция, вычитание
/: математическая функция, деление
Sqrt: математическая функция, возвращает корень числа.
Корень может быть любой степени
Mod: математическая функция, возвращает остаток от
деления
Int: математическая функция, возвращает целая часть числа
Frac: математическая функция, возвращает дробная часть
числа
Random: математическая функция, возвращает произвольное
число от 0 до 1
Trunc: математическая функция, возвращает целую часть
числа
Round: математическая функция, округляет число
Sin: математическая функция, возвращает синус числа
ArcSin: математическая функция, возвращает арксинус числа
Sinh: математическая функция, возвращает гиперболический
синус числа
ArcSinh: математическая функция, возвращает
гиперболический арксинус числа
Cos: математическая функция, возвращает косинус числа
ArcCos: математическая функция, возвращает арккосинус
числа
Cosh: математическая функция, возвращает гиперболический
косинус числа
ArcCosh: математическая функция, возвращает
гиперболический арккосинус числа
Tan: математическая функция, возвращает тангенс числа
ArcTan: математическая функция, возвращает арктангенс
числа
Tanh: математическая функция, возвращает гиперболический
тангенс числа
ArcTanh: математическая функция, возвращает
гиперболический арктангенс числа
CoTan: математическая функция, возвращает котангенс числа
ArcCoTan: математическая функция, возвращает арккотангенс
числа
CoTanh: математическая функция, возвращает
гиперболический котангенс числа
ArcCoTanh: математическая функция, возвращает
гиперболический арккотангенс числа
Sec: математическая функция, возвращает секанс числа
ArcSec: математическая функция, возвращает арксеканс
числа
Sech: математическая функция, возвращает гиперболический
секанс числа
ArcSech: математическая функция, возвращает
гиперболический арксеканс числа
ArcCsc: математическая функция, возвращает арккосеканс
числа
Csc: математическая функция, возвращает косеканс числа
ArcCsc: математическая функция, возвращает
гиперболический арккосеканс числа
Csc: математическая функция, возвращает гиперболический
косеканс числа
Abs: математическая функция, возвращает абсолютную
величину числа
Ln: математическая функция, возвращает натуральный
логарифм числа
Lg: математическая функция, возвращает десятичный
логарифм числа
Log: математическая функция, возвращает логарифм двух
числа
Pi: математическая функция, возвращает число Пи
!: математическая функция, возвращает факториал числа
^: математическая функция, возвращает степень числа.
Степень может быть дробной
Несколько слов о тех изменениях, которые я
сделал. Прежде всего, улучшен контроль ошибок. Теперь идет строгая проверка
последовательности функций с учетом их особенностей. Также доработаны сообщения
исключительных ситуаций о найденных ошибках. Изменено зарезервированное слово
"bool" на "if", которое служит для обозначения логических выражений. На мой
взгляд "if" намного лучше, короче и, как Вы заметили, я стараюсь сделать
элементы синтаксиса формулы максимально похожими на те же элементы в Delphi.
Изменено свойство "Formula", теперь это свойство "Text". Изменены названия
методов для работы с математическим сценарием, например RegisterIntFunction
теперь называется RegisterNumFunction. Раньше при регистрации функций важно было
следить за их порядком. Поясню на примере. Представьте себе, что Вы
регистрируете новую функцию "X". А затем Вы регистрируете еще одну функцию
"EXP". В памяти программы они будут находиться именно в порядке регистрации,
т.е. сначала "X", затем "EXP". При распознавании формулы в таком же порядке
будет происходить поиск функций. Поэтому функция "EXP" никогда не будет
распознана, т.к. она включает себя функцию "X", которая будет найдена первой.
Сейчас порядок регистрации не имеет значения. Но после регистрации нужно вызвать
метод SortNumFunctionsData или SortBoolFunctionsData для соответственно
математических и логических функций. Эти методы сортируют зарегистрированные
функции таким образом, что первыми оказываются самые "длинные" функции. После
регистрации новых типов нужно вызвать метод SortTypesData. Важно помнить, что
после сортировки функций, изменятся идентификаторы этих функции в соответствии с
их новым положением в памяти. Опять же я приведу пример. Представьте, что Вы
регистрируете две новые функции, пусть это будут функции "sin" и "sinh" (такие
функции регистрируются автоматически при создании объекта класса TDataEditor, но
пример чисто гипотетический):
...
type
TForm1 = class(TForm)
...
private
FSinID: Integer;
FSinhID: Integer;
...
end;
...
procedure TForm1.FormCreate(Sender: TObject);
begin
with DataEditor do begin
RegisterNumFunction(FSinID, 'sin', False, True);
RegisterNumFunction(FSinhID, 'sinh', False, True);
// Допустим, что FSinID = 0, FSinhID = 1;
SortNumFunctionsData;
// После выполнения этой процедуры, FSinID = 1, FSinhID = 0,
// т.е. первой функцией стала наиболее длинная - 'sinh'.
end;
...
end;
...
Пример
В качестве
примера использования класса TDataEditor я написал компонент (TGraph), который
строит графики функций. А также я сделал ActiveX объект, который демонстрирует
возможности компонента TGraph. ActiveX Вы можете увидеть чуть ниже, но сначала
несколько слов о методах и свойствах TGraph:
function XCoord(X: Double): Double; возвращает координату оси X в масштабе
графика. Параметр функции X указывается в масштабе компонента
function YCoord(Y: Double): Double; возвращает координату оси Y в масштабе
графика. Параметр функции Y указывается в масштабе компонента
function Coordinates(X, Y: Double): TCoord;
TCoord = record
X, Y: Double;
end;
возвращает координаты в масштабе графика. Параметры функции X и Y
указывается в масштабе компонента
property Picture: TBitmap; содержит изображение графика
property Detailization: Integer; уровень детализации графика. Это свойство
регулирует количество точек, которые будут рассчитаны начиная с минимального
до максимального значений оси X. При повышении детализации, повышается
количество расчетных точек на оси X, соответственно повышается количество
соответствующих им точек Y. Поэтому эффект от повышения детализации заметнее
на графиках типа Y = TAN X, где больше вертикальных линий (практически нет
смысла детализировать функции типа Y = X или Y = SIN X). После расчета графика
создается массив точек, который затем подвергается фильтрации (чтобы избежать
двух точек с одинаковыми координатами - побочный эффект чрезмерной
детализации).
property FramePen: TPen; отвечает за прорисовку линии рамки
property GraphPen: TPen; отвечает за прорисовку линии графика
property GridPen: TPen; отвечает за прорисовку линии координатной сетки
property HorzSpacing: Double; шаг координатной сетки по горизонтали
property ShowAxis: Boolean; определяет видимость координатных осей
property ShowFrame: Boolean; определяет видимость рамки
property ShowGrid: Boolean; определяет видимость координатной сетки
property ShowText: Boolean; определяет видимость формулы
property Text: string; содержит формулу
property TracePen: TPen; отвечает за прорисовку линий трассировки
property Tracing: Boolean; определяет трассировку графика
property VertSpacing: Double; шаг координатной сетки по вертикали
property XMaxValue: Integer; максимальное значение оси X
property YMaxValue: Integer; максимальное значение оси Y
property OnTrace: TTraceEvent; TTraceEvent = procedure(Sender: TObject; X,
Y: Double; var Continue: Boolean) of object; событие, возникает при
трассировки графика. Параметры X, Y возвращают координаты текущей точки,
параметр Continue позволяет прекратить трассировку
На рисунке приведен
скриншот ActiveX-компонента, который Вы можете установить у себя, скачав
предлагаемый проект, или проведя on-line тестирование на страницах
Королевства. Прежде чем переходить по ссылке, обратите внимание, придется
скачать ActiveX размером 304К.
При
составлении этого примера я оставил доступными все математические функции,
которые были перечислены выше. Вообще функции типа "random", "frac" или "int" с
точки зрения математики не желательны. Но при использовании некоторых из них
получаются очень любопытные графики (например, int abs x ^ frac abs x или random
* x * sin x). Обратите также внимание, что при изменении максимальных значений
осей X или Y перерасчет графика происходит практически мгновенно.
Заключение
Хочу
выразить отдельную благодарность Григорьеву Антону за его
статью "Неочевидные особенности
вещественных чисел". В этих компонентах сплошь и рядом используются
вещественные числа, без дополнительной информации сделать их было бы сложнее.
Исходники: