Mathematical formula compiler&evaluator - VCL Component
for Delphi.
TRyFormulaEval is a native Delphi component designed to
evaluate mathematical formulas. Performace of this evaluation is improved
by compiling the formula to assembler code, internally. TRyFormulaEval
implements parse once-evaluate many times type of parsing for mathematical
expressions given as strings. It allows creation of custom variables and
functions to be used in the expressions; once defined, functions can be
redefined in runtime and extremely fast, resulting a very powerful tool.
Its internal arithmetic uses ‘Extended’ storage for floating
point numbers.
Variable values can be set in three different ways: OnFindVariable
event oriented, reference by name, reference by index. Thread safe.
Features
Unsupported features
RyFormulaEval is an optimized numerical mathematical formula evaluator,
so these features are not supported:
Installation
No installation needed. Just include RyFormulaEval.pas (or dcu) in your
project and add it to the uses clause/s.
Properties, Methods and Events
Types
PVariable = ^TVariable;
TVariable = record
Value: Extended;
end;
TExprMathFunction = function(var values: array of Extended):
Extended of object;
TExprMathOnFindVariable = procedure(VariableName: string; var
Value: Extended) of object;
Properties
Formula: string
Result: Extended
VarCount: Integer
VarByName[VariableName: string]: PVariable
VarByIndex[Idx: Integer]: PVariable
Methods
function GetVarIndex(VariableName: string): Integer;
function AddFunctionDecl(FunctionName: string; NumParams:
Integer;
CustomFunction: TExprMathFunction): Boolean;
function ModifyFunctionDecl(FunctionName: string;
CustomFunction: TExprMathFunction): Integer;
function ResultNOCompile: Extended;
procedure Parse;
procedure Compile;
procedure UseStandardFunctions;
constructor Create;
destructor Destroy; override;
Events
OnFindVariable: TExprMathOnFindVariable
Properties, Methods and Events description
Formula Text of the formula.
Result Result of current evaluation
VarCount Number of variables
VarByIndex[Idx: Integer] Variable number Idx
VarByName[varName: string] Variable with name = varName
OnFindVariable: Event triggered when an unknown variable is found
GetVarIndex Returns the index of variable with the name
specified
AddFunctionDecl Declares a new external function
ModifyFunctionDecl Redirects a function declaration
ResultNOCompile Result of current evaluation without compiling
code.
Parse Invokes explicit formula parse.
Should be called only once after setting formula.
Compile Invokes explicit formula compilation.It is called
automatically the first time a result is requested.
UseStandardFunctions Activates standard functions.
Create Constructor.
Destroy Destructor.
Demo version limitations
RyFormulaEval demo version will NOT:
Handle more than 8 distinct variables
Support division or power operations
Allow user to declare external functions with more than one parameter.
Code sample
This a sample that demonstrates the use of independent computation threads,
UnitThreads.pas
***********************************************************************
unit UnitThreads;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, RYFormulaEvaluator, StdCtrls, ExtCtrls;
type
TComputationThread = class(TThread)
private
aExpr: TRyFormulaEval;
procedure FindVar(VariableName: string; var Value:
Extended);
public
LastResult: Extended;
procedure Execute; override;
constructor Create(Susp: Boolean);
destructor Destroy; override;
end;
TForm2 = class(TForm)
Button1: TButton;
Label1: TLabel;
Lblnum: TLabel;
Memo1: TMemo;
Timer1: TTimer;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
l: TList;
Num: Integer;
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.DFM}
{ TComputationThread }
constructor TComputationThread.Create(Susp: Boolean);
begin
inherited Create(True);
aExpr := TRyFormulaEval.Create;
aExpr.UseStandardFunctions;
aExpr.OnFindVariable := FindVar;
aExpr.Formula := 'PERCENT(x, MAX(x, y) * MIN(((k))*l+o, u))';
aExpr.Parse;
Priority := tpNormal;
end;
destructor TComputationThread.Destroy;
begin
aExpr.Free;
inherited;
end;
procedure TComputationThread.Execute;
begin
while not Terminated do
begin
LastResult := aExpr.Result;
sleep(20);
end;
end;
procedure TComputationThread.FindVar(VariableName: string;
var Value: Extended);
begin
if VariableName = 'x' then
Value := 10
else if VariableName = 'y' then
Value := Random(2000)
else if VariableName = 'k' then
Value := 30.67
else if VariableName = 'l' then
Value := 234
else if VariableName = 'o' then
Value := 567
else if VariableName = 'u' then
Value := 2.245;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
ct: TComputationThread;
begin
ct := TComputationThread.Create(True);
ct.Resume;
l.Add(ct);
Inc(Num);
LblNum.Caption := IntToStr(Num);
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
l := TList.Create;
Num := 0;
end;
procedure TForm2.FormDestroy(Sender: TObject);
var
t: TThread;
begin
while l.Count > 0 do
begin
t := l.Items[0];
t.Terminate;
t.WaitFor;
t.Free;
l.Delete(0);
end;
l.Free;
end;
procedure TForm2.Timer1Timer(Sender: TObject);
var
k: Integer;
t: TComputationThread;
begin
if Assigned(l) and (l.Count > 0) then
begin
if Memo1.Lines.Count > 200 then
Memo1.Lines.Clear;
Memo1.Lines.Add('-----------------------------------------');
for k := 0 to l.Count-1 do
begin
t := l.Items[k];
Memo1.Lines.Add('THR'+ Format('%4.4d=%f',
[k, t.LastResult]));
end;
Memo1.Lines.Add('-----------------------------------------');
end;
end;
end.
UnitThreads.dfm
***********************************************************************
object Form2: TForm2
Left = 157
Top = 295
Width = 396
Height = 251
Caption = 'RYFormula Evaluator thread test'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 192
Top = 8
Width = 64
Height = 13
Caption = 'NumThreads:'
end
object Lblnum: TLabel
Left = 264
Top = 8
Width = 32
Height = 13
Caption = 'lblNum'
end
object Button1: TButton
Left = 16
Top = 8
Width = 153
Height = 25
Caption = 'Add computation thread !'
TabOrder = 0
OnClick = Button1Click
end
object Memo1: TMemo
Left = 16
Top = 48
Width = 353
Height = 169
Lines.Strings = (
'')
TabOrder = 1
end
object Timer1: TTimer
Interval = 200
OnTimer = Timer1Timer
Left = 336
Top = 8
end
end
License Agreement
This code is shareware. No warranties, express or implied, are provided.
The author is not responsible for any problems caused by this component.
Use it at your own risk. The author provides no support whatsoever, and
is not obligated to any person or corporation for anything related to this
software. The author reserves all rights concerning this code. You are
free to evaluate it and distribute it for evaluation purposes, if you do
not modify any part of it and you distribute all the files as a whole.
This code cannot be sold for any purposes, or included in a commercial
collection, without the express written consent of the author.
This License Agreement applies to demo version only, please read the
the registration section for more information. By installing these
files on your computer, you agree to all above conditions.
(C)opyright 2000, Reinaldo Yañez Arrey.
Buenos Aires, Argentina.
rya@labs.df.uba.ar
ryaayr@yahoo.com