
Краткое описание
Компонент предназначен для вычисления заданного математического выражения
Параметры
Методы
События
Свойства
Примеры
Пример простейшего использования компонента MathParse
Add(MainForm,2603728,189,63)
{
Caption="Пример использования MathParse"
}
Add(Edit,437523,245,63)
{
Left=33
Top=105
Text="25"
}
Add(Edit,2314167,301,63)
{
Left=96
Top=105
Text="35"
}
Add(Button,5611198,245,133)
{
Left=227
Top=105
link(onClick,15349949:doCalc,[])
}
Add(MathParse,15349949,294,133)
{
DataCount=3
MathStr="%1 + %2 / %3"
link(onResult,14627873:doText,[])
link(X1,437523:Text,[(300,114)(251,114)])
link(X2,2314167:Text,[])
link(X3,9630350:Text,[(314,114)(356,114)])
}
Add(Edit,14627873,350,133)
{
Left=297
Top=105
Width=55
}
Add(Edit,9630350,350,63)
{
Left=160
Top=105
Text="2"
}
Пример использования компонента MathParse с округлением до нужного кол-ва знаков
Add(MainForm,4985402,77,84)
{
Caption="Пример использования MathParse"
}
Add(MathParse,9740776,182,154)
{
DataCount=3
MathStr="round(%1 / %2, %3)"
link(onResult,180755:doText,[])
link(X1,13188300:Text,[(188,135)(139,135)])
link(X2,9231152:Text,[])
link(X3,5383578:Text,[(202,135)(244,135)])
}
Add(Edit,180755,238,154)
{
Left=225
Top=75
Width=55
Text=""
}
Add(Edit,13188300,133,84)
{
Left=105
Top=75
Width=55
Text="4"
DataType=2
}
Add(Edit,9231152,189,84)
{
Left=165
Top=75
Width=55
Text="3"
DataType=2
}
Add(Button,14190716,133,154)
{
Left=105
Top=125
link(onClick,9740776:doCalc,[])
}
Add(Edit,5383578,238,84)
{
Left=105
Top=100
Width=55
Text="0.01"
DataType=4
}
Пример использования MathParse для нахождения min и max
Add(MathParse,4780479,252,175)
{
DataCount=4
MathStr="min(%1, %2, %3, %4)"
link(onResult,10627641:doText,[])
link(X1,8188835:Var2,[])
link(X2,8833312:Var1,[(265,145)])
link(X3,3926228:Var1,[(272,152)])
link(X4,7101616:Var1,[(279,159)])
}
Add(MainForm,13771273,154,98)
{
Width=318
Height=144
Caption="Пример использования MathParse"
}
Add(Label,7001549,252,56)
{
Left=10
Top=15
Width=11
Height=17
Caption="A"
}
Add(Edit,9764418,252,98)
{
Left=25
Top=12
Text="4"
}
Add(Edit,3192347,287,98)
{
Left=100
Top=12
Text="6"
}
Add(Edit,10627641,420,175)
{
Left=75
Top=47
Text=""
}
Add(Edit,12123487,420,217)
{
Left=205
Top=47
Text=""
}
Add(Button,4513443,154,175)
{
Left=126
Top=80
Caption="MinMax"
link(onClick,15969813:doEvent1,[])
}
Add(Hub,15969813,210,175)
{
link(onEvent1,4780479:doCalc,[])
link(onEvent2,11247982:doCalc,[(239,188)(239,223)])
}
Add(Label,2817402,287,56)
{
Left=85
Top=15
Width=11
Height=17
Caption="B"
}
Add(Label,5611803,462,175)
{
Left=45
Top=50
Width=21
Height=17
Caption="Min"
}
Add(Label,14871279,462,217)
{
Left=175
Top=50
Width=24
Height=17
Caption="Max"
}
Add(Edit,803595,322,98)
{
Left=175
Top=12
Text="1"
}
Add(Label,4045316,322,56)
{
Left=160
Top=15
Width=11
Height=17
Caption="C"
}
Add(Edit,12583063,357,98)
{
Left=250
Top=12
Text="3"
}
Add(Label,4912119,357,56)
{
Left=235
Top=15
Width=12
Height=17
Caption="D"
}
Add(MathParse,11247982,364,217)
{
DataCount=4
MathStr="max(%1, %2, %3, %4)"
link(onResult,12123487:doText,[])
link(X1,8188835:Var3,[(370,138)])
link(X2,8833312:Var3,[(377,145)])
link(X3,3926228:Var3,[(384,152)])
link(X4,7101616:Var3,[(391,159)])
}
Add(GetDataEx,8188835,252,133)
{
link(Data,9764418:Text,[])
}
Add(GetDataEx,8833312,287,140)
{
link(Data,3192347:Text,[])
}
Add(GetDataEx,3926228,322,147)
{
link(Data,803595:Text,[])
}
Add(GetDataEx,7101616,357,154)
{
link(Data,12583063:Text,[])
}
Альтернативный вариант нахождения min и max, используя функции "x > y"
Add(MainForm,969937,210,84)
{
Width=271
Height=238
Caption="Пример использования MathParse"
}
Add(Label,7001549,308,42)
{
Left=25
Top=15
Width=11
Height=17
Caption="A"
}
Add(Label,2817402,371,42)
{
Left=145
Top=15
Width=11
Height=17
Caption="B"
}
Add(Edit,9764418,308,84)
{
Left=50
Top=12
Text="7"
}
Add(Edit,3192347,371,84)
{
Left=180
Top=12
Text="6"
}
Add(Label,5611803,462,168)
{
Left=25
Top=165
Width=11
Height=17
Caption="MIN"
}
Add(Label,14871279,462,217)
{
Left=145
Top=165
Width=11
Height=17
Caption="MAX"
}
Add(Edit,10627641,413,168)
{
Left=50
Top=162
Text=""
}
Add(Edit,12123487,413,217)
{
Left=180
Top=162
Text=""
}
Add(Button,4513443,210,168)
{
Left=105
Top=95
link(onClick,15969813:doEvent1,[])
}
Add(MathParse,6888583,308,168)
{
MathStr="(%1 > %2) * %2 + (%1 <= %2) * %1"
Point(doMathStr)
link(onResult,10627641:doText,[])
link(X1,9998433:Var2,[])
link(X2,12887404:Var1,[(321,138)])
}
Add(MathParse,15914977,364,217)
{
MathStr="(%1 < %2) * %2 + (%1 >= %2) * %1"
Point(doMathStr)
link(onResult,12123487:doText,[])
link(X1,9998433:Var3,[(370,131)])
link(X2,12887404:Var2,[])
}
Add(Hub,15969813,266,168)
{
link(onEvent1,6888583:doCalc,[])
link(onEvent2,15914977:doCalc,[(296,181)(296,223)])
}
Add(GetDataEx,9998433,308,126)
{
link(Data,9764418:Text,[])
}
Add(GetDataEx,12887404,371,133)
{
link(Data,3192347:Text,[])
}
Замечания
Элемент поддерживает использование внешних функций, обращение к элементам массивов, матриц, к функциональным блокам. А также предоставляет возможность внешнего распознавания <Имен>, отличных от встроенных (которые перечислены ниже).
Пример: %1+2*sh(%2(3)) - первый аргумент делает вызов с точки X1, отправляя наверх данные типа NULL (т.е. ничего); второй же аргумент отправляет наверх данные (3.0) типа real и получает результат работы функционального блока, подключенного к этой точке (а он уже и используется в вычислениях). Таким функциональным блоком может быть такой же MathParse со своей формулой и подключенный к точке reCalc, либо целая схема на HiAsm. Синтаксис использования массивов и матриц аналогичен, но использует квадратные скобки: %5[2] - второй элемент массива, подключенного к точке X5; %1[%2*4, %3+1] - соответствующий элемент матрицы, подключенной к точке X1. Понятно, что в качестве аргументов функционального вызова могут стоять полноценные выражения.
Для квадратных скобок количество аргументов определено естественным образом: если один - это массив, а если два - это матрица. В случае функционального вызова (круглые скобки) - таких ограничений нет. Если в формуле записаны несколько аргументов - все рассчитанные аргументы будут содержаться в MT-потоке, отправляемом наверх. Первый аргумент - в голове потока, в соответствии с описанным выше. Например, можно было написать: %1+2*sh(%2(3, %1)) - и наверх уже ушли бы два числа. Первое - 3.0, как и раньше. И второе (в MT-хвосте) - значение первого аргумента.
В некоторых случаях, на этапе дизайна схемы невозможно определить ни количество требуемых функциональных вызовов, ни количество аргументов к каждому. Например, если формулу для вычисления определяет пользователь: 1/(2*pi*sqrt(L*C)). Если бы эта формула была известна заранее, то мы ее записали бы так: 1/(2*pi*sqrt(%1*%2)), и подключили бы две верхних точки к нужным участкам схемы. А вот если мы ничего не знаем про формулу, но вводим ее методом doMathStr, тогда у нас есть возможность сделать внешнее распознавание имен - то ли там совсем глупость написана, то ли это имя содержится в какой-нибудь базе, то ли еще что-нибудь... Без ограничения творческих возможностей разработчика схемы.
Включается таковая возможность назначением свойству ExtNames номера реальной верхней точки элемента. По умолчанию - эта возможность выключена. В режиме же внешнего распознавания - наверх (через точку с номером ExtNames) отправляются данные типа string, содержащие обнаруженное в формуле неизвестное <Имя>.
Пример такового внешнего распознавания может выглядеть так:
Add(MainForm,12091017,357,140)
{
Width=383
Height=168
Position=1
}
Add(MathParse,13609475,210,140)
{
DataCount=1
MathStr=""
ExtNames=1
Point(onError)
Point(doMathStr)
link(onResult,8776525:doOperation,[])
link(X1,14343204:GetData,[])
}
Add(Button,720514,70,133)
{
Left=293
Top=20
Width=69
Height=55
Caption="А ну ка посчитай"
Data=Integer(2)
link(onClick,179976:doEvent1,[])
}
Add(EventFromData,14343204,210,84)
{
link(onEvent,5059389:doCompare,[])
}
Add(Edit,6679953,308,35)
{
Left=14
Top=14
Width=63
Height=28
Font=[MS Sans Serif,12,1,0,1]
Text="L"
Alignment=2
}
Add(Edit,7640271,259,35)
{
Left=14
Top=49
Width=63
Height=28
Font=[MS Sans Serif,12,1,0,1]
Text="C"
Alignment=2
}
Add(Edit,11638121,357,35)
{
Left=98
Top=14
Width=175
Height=28
Font=[MS Sans Serif,12,1,0,1]
Text="150e-6"
Alignment=1
DataType=4
}
Add(Edit,15259230,406,35)
{
Left=98
Top=49
Width=175
Height=28
Font=[MS Sans Serif,12,1,0,1]
Text="200e-6"
Alignment=1
DataType=4
}
Add(Edit,11411693,154,42)
{
Left=14
Top=91
Width=350
Height=28
Font=[MS Sans Serif,12,1,0,1]
Text="1/(2*pi*sqrt(L*C))"
Alignment=2
}
Add(DoData,4311203,357,91)
{
link(onEventData,7947405:doWork2,[])
link(Data,11638121:Text,[])
}
Add(Hub,179976,119,133)
{
link(onEvent1,11360630:doData,[])
link(onEvent2,13609475:doCalc,[])
}
Add(DoData,7345327,406,84)
{
link(onEventData,7947405:doWork1,[(452,90)])
link(Data,15259230:Text,[])
}
Add(DoData,11360630,154,133)
{
link(onEventData,13609475:doMathStr,[(193,139)(193,153)])
link(Data,11411693:Text,[])
}
Add(FormatStr,15788014,308,140)
{
DataCount=1
Mask="Резонансная частота контура: %1 Гц "
link(onFString,12091017:doCaption,[])
}
Add(Math,8776525,259,140)
{
OpType=35
Op2=0.1
link(onResult,15788014:doString,[])
}
Add(If_else,5059389,259,84)
{
link(onTrue,7345327:doData,[])
link(onFalse,9315578:doCompare,[])
link(Op1,7640271:Text,[])
}
Add(Memory,685729,469,91)
{
link(onData,14343204:doData,[(515,97)(515,76)(200,76)(200,90)])
}
Add(If_else,9315578,308,91)
{
link(onTrue,4311203:doData,[])
link(onFalse,685729:doClear,[])
link(Op1,6679953:Text,[])
}
Add(HubEx,7947405,448,91)
{
link(onEvent,685729:doValue,[])
}
Например, в формуле из примера можно было бы написать C(45) - скажем, значение емкости при температуре 45 градусов. Аналогичным образом, количество таких аргументов специально не ограничивается. Элемент MathParse, передавши нужное количество данных наверх -- лишь анализирует данные, которые ему вернут. Как будут использованы (и будут ли использованы вообще) переданные перед этим данные наверх - его не беспокоит. Но, надо отметить, что если это будет NULL - это будет воспринято как ошибка. Либо в схеме ничего не подключего вообще, либо Имя не опознано.
Поддержана возможность итеративных вычислений без внешнего элемента Memory. Можно в формуле обратиться к результату предыдущих вычислений (%0) и сбросить значение результата (перед началом операций) методом doClear в значение, определяемое свойством Default.
Возможно проведение нового вычисления по запросу на нижнюю точку reCalc. При этом данные, поступившие снизу выполняют роль данных (в т.ч. и MT-данных) из потока при запуске вычислений методом doCalc. В общем MathParse-ы можно вертикально каскадировать, причем верхний MathParse будет вызываться нижним сколько раз, сколько потребуется в формуле.
При ошибках в вычислении, кроме ее типа (Синтаксис, Вычисления), доступна позиция в исходной строке, на которой анализатор элемента отказался продолжать. Это можно прочитать с нижней точки PosErr. Следует отметить, что при наличии ошибки, событие onResult не генерируется, но onError - обязательно. После ошибки - с нижней точки Result читается NULL, а при отсутствии ошибки в предыдущем вычислении - с нижней точки PosErr читается -1 (несуществующая позиция в строке). Метод doClear сбрасывает состояние ошибки. Метод doCalc (как и reCalc) после ошибки автоматически делает doClear.
Внимание! Порядок вызова верхних точек отличается от общепринятого (слева направо). Он определяется только формулой MathStr. При этом, если какой-то аргумент вызывался один раз, и он не является функциональным, то вызов производится только один раз. Это же касается и данных из потока, которые используются в качестве первого же аргумента, у которого верхняя точка свободна. Ну а функциональные вызовы (как и вызовы матриц и массивов) осуществляются столько раз, сколько встречаются в формуле. Поскольку это могут быть, например, элементы массива от разных значений индекса. Пример, демонстрирующий порядок вызова аргументов: Хотим посчитать биномиальный коэффициент N!/K!/(N-K)! Для этого, например, подключаем к точке X1 - значение N, к точке X2 - значение K, а к точке X3 - функциональный блок, вычисляющий факториал. Записываем формулу: %3(%1)/%3(%2)/%3(%1-%2)
Add(Button,12525146,168,210)
{
Left=130
Top=40
link(onClick,4272500:doCalc,[])
}
Add(Edit,8205226,217,140)
{
Left=45
Top=55
Text="4"
DataType=1
}
Add(Edit,13874763,259,140)
{
Left=45
Top=25
Text="2"
DataType=1
}
Add(Edit,11471828,322,210)
{
Left=210
Top=40
Width=120
Text=""
}
Add(MathParse,4272500,252,210)
{
DataCount=3
MathStr="%3(%1)/%3(%2)/%3(%1-%2)"
link(onResult,11471828:doText,[])
link(X1,8205226:Text,[(258,191)(223,191)])
link(X2,13874763:Text,[])
link(X3,859993:GetData,[(272,191)(321,191)])
}
Add(EventFromData,859993,315,140)
{
link(onEvent,4726931:doEvent1,[])
link(Data,13765667:Var1,[(321,128)])
}
Add(For,8900009,406,147)
{
End=2
Step=-1
InData=0
link(onEvent,9810269:doOperation,[])
link(onStop,859993:doData,[(449,160)(449,185)(307,185)(307,146)])
}
Add(Math,9810269,469,147)
{
OpType=2
Default=1
Point(doClear)
link(Op2,13765667:Var2,[])
}
Add(Hub,4726931,364,140)
{
link(onEvent1,9810269:doClear,[(457,146)(457,160)])
link(onEvent2,8900009:doFor,[])
}
Add(GetDataEx,13765667,469,119)
{
Angle=1
link(Data,9810269:Result,[(510,128)(510,191)(475,191)])
}
MathParser имеет следующие встроенные математические функции:
Использование функции | Краткое описание функции |
x + y | сложение |
x - y | вычитание |
x * y | умножение |
x / y | деление |
x ^ y | возведение в степень |
x div y | целочисленное деление(извлечение целой части) |
x mod y | остаток от деления |
cos(x) | косинус угла, в зависимости от AngleMode (по умолчанию - в радианах) |
sin(x) | синус угла, в зависимости от AngleMode (по умолчанию - в радианах) |
tg(x) | тангенс угла, в зависимости от AngleMode (по умолчанию - в радианах) |
ctg(x) | котангенс угла, в зависимости от AngleMode (по умолчанию - в радианах) |
arccos(x) | арккосинус, результат - в зависимости от AngleMode (по умолчанию - в радианах) |
arcsin(x) | арксинус, результат - в зависимости от AngleMode (по умолчанию - в радианах) |
ln(x) | натуральный логарифм числа |
sqrt(x) | квадратный корень числа |
atan(y,x) | угол, определяемый точкой с координатами (x,y), результат - в зависимости от AngleMode (по умолчанию - в радианах) |
ch(x) | гиперболический косинус (exp(x)+exp(-x))/2 |
sh(x) | гиперболический синус (exp(x)-exp(-x))/2 |
th(x) | гиперболический тангенс sh(x)/ch(x) |
cth(x) | гиперболический котангенс ch(x)/sh(x) |
arcch(x) | обратная ch(x) |
arcsh(x) | обратная sh(x) |
arcth(x) | обратная th(x) |
arccth(x) | обратная cth(x) |
log(n,x) | логарифм от x по основанию: n ln(x)/ln(n) |
lg(x) | десятичный логарифм ln(x)/ln(10) |
exp(x) | экспонента: e^x |
sqr(x) | просто квадрат: x*x |
abs(x) | абсолютная величина числа |
sign(x) | знак числа, принимает соответственно значения -1,0,+1 |
round(x[,y=1]) | округление к ближайшему целому, round(x,y)=y*round(x/y) |
frac(x[,y=1]) | дробная часть, frac(x,y)=y*frac(x/y) |
trunc(x[,y]) | отбрасывание дробной части, trunc(x,y)=y*trunc(x/y) |
floor(x[,y=1]) | округление x до ближайшего меньшего целого |
ceil(x[,y=1]) | округление x до ближайшего большего целого |
odd(x) | если round(x) нечетный, возвращает 1, иначе - 0 |
even(x) | если round(x) четный, возвращает 1, иначе - 0 |
min(x[,y ...]) | находим минимум от всех аргументов |
max(x[,y ...]) | находим максимум от всех аргументов |
pi | возвращает число ПИ = 3.141592653589793... |
e | возвращает число e = 2.718281828459045... |
x < y | принимает значения 1, если выполняется условие, иначе - 0 |
x > y | принимает значения 1, если выполняется условие, иначе - 0 |
x <= y | принимает значения 1, если выполняется условие, иначе - 0 |
x >= y | принимает значения 1, если выполняется условие, иначе - 0 |
x = y | принимает значения 1, если выполняется условие, иначе - 0 |
x <> y | принимает значения 1, если выполняется условие, иначе - 0 |
x and y | принимает значения 1, если x <> 0 и y <> 0, иначе - 0 |
x or y | принимает значения 1, если x <> 0 или y <> 0, иначе - 0 |
x xor y | принимает значения 1, если x = 0 и y <> 0, или x <> 0 и y = 0, иначе - 0 |
Обновление элемента: [svn]MathParse.pas[/svn]