Вверх ↑
Ответов: 18
Рейтинг: 0
#1: 2013-05-19 17:51:03 ЛС | профиль | цитата
Ну давайте почитаем...

MathParse

Краткое описание
   Компонент предназначен для вычисления заданного математического выражения

Параметры
  • DataCount - Кол-во аргументов (нумеруются от %1 до %DataCount, %0 - значение результата)
  • MathStr - Вычислительная формула, установленная с самого начала, до применения метода doMathStr
  • ResultType - Тип результата. Может быть Real (по умолчанию) и Integer
  • Default - Значение результата, которое можно прочитать методом Result (или как %0 в формуле) в самом начале, или после метода doClear
  • AngleMode - Режим работы тригонометрических функций. Угловые данные могут восприниматься/возвращаться либо в радианах (по умолчанию) либо в градусах
  • ExtNames - Номер верхней точки, на которую выдается текстовый запрос (с опциональными Real-аргументами в виде MT-хвоста) при синтаксическом распознавании неизвестного Имени. Работает только для случая: 0<ExtNames<=DataCount
    Методы
  • doCalc - Вызывает процесс синтаксического разбора формулы и вычисления результата
  • doMathStr - Устанавливает строку для математического разбора методами doCalc и reCalc
  • doClear - Сбрасывает состояние ошибки: св-во PosErr принимает значение -1, а Result принимает значение Default
    События
  • onResult - Происходит после успешного вычисления методом doCalc (в случае неуспеха - onError) и выдает результат в поток
  • onError - Происходит при ошибке по методу doCalc. В поток выдается целое число: 0 - соответствует синтаксической ошибке, а 1 - ошибке вычислений. Если точка не подключена, сообщение об ошибке выдается в окно Debug
    Свойства
  • Result - Хранит результаты предыдущего вычисления. Если была ошибка - возвращает NULL
  • reCalc - Метод, альтернативный doCalc. Данные из потока снизу выполняют ту же функцию, что и данные входного потока в методе doCalc. Однако события onResult или onError не происходят, а результат возвращается обратно в вызвавший поток. Если произошла ошибка, возвращается NULL
  • PosErr - Номер позиции в строке (начинается с нуля) при возникновении ошибки при использовании методов doCalc и reCalc. Если последний вызов этих методов окончился успешно, хранит -1
    Примеры
    Пример простейшего использования компонента 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)])
    }
    При вычислении, обращения будут происходить в следующей последовательности (читайте строку слева направо): [точка X1] => [точка X3 с соответствующим аргументом] => [точка X2] => [точка X3 с соответствующим аргументом] => [точка X3 с нужным аргументом, значения с X1 и X2 уже известны].

       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]
  • карма: 2
    пугаться не надо ...
    0