FormulaEval
 
TRyFormulaEval Component, by Reinaldo Yañez Arrey.
Copyright © 2000 Reinaldo Yañez Arrey.
All Rights Reserved.
rya@labs.df.uba.ar; ryaayr@yahoo.com
Version 2.0
 
 

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