Function Evaluator

Environment: Visual C# Ver 1.0, .NET Platform Ver 1.0, Windows XP, Windows 2000 SP2

Abstract

This program uses the transformation from infix notation to postfix notation to evaluate most mathematic expressions. It supports most operators (+, -, *, /, %, and ^), functions from 0 to any number of parameters, and also a user-defined function by using a delegate. Also, it supports variables in the expression; it will generate a symbol table that can be updated at run time. Also, this program demonstrates the use of a DataGrid as a normal grid without any database connection.

Details

All the code neccessary to transform an infix expression to a postfix expression and evaluate the postfix expression is encapsulated in the "Function" class. Also, this class supports a variable; this means you can write expressions such as "num1 + num2". It automatically generates the symbol table for it, and initializes all variables to zero by default.

The first member function that must be called in the Function class is "Parse", which takes the expression string as a parameter and transforms it to an an "ArrayList" of Symbol, and stores it in the member variable "m_equation". The Symbol is a structure that contains information about any symbol, which is the smallest element in any equation. It contains the following information:

  • m_name: the name of the symbol which may be "num1", "+", "cos" ,"(", "7", and so forth.
  • m_type: the type of this symbol that is defined in the enumerator Type, which may be variable, value, operator, comma, and so on.
  • m_value: the value of that symbol valid only if it is a variable or value.

After that, you must call the member function "Infix2Postfix", which transforms the infix notation stored in m_equation to postfix notation and stores it in the m_postfix member variable. If the expression contain any variables, you can call the Variables property to get the symbol table as an ArrayList of Symbol structures. This array contains all variable type symbols only. After changing the value of any variable, just call the "Variables" property again and put on it the updated symbol table. This property is both get and set.

After that, you can call the member function "EvaluatePostfix" to evaluate the expression. The result will be stored as a double in the m_result member variable, which can be accessed by the property member "Result".

Also, this Class has a number of defined functions that can be used directly in any expression. These functions are case sensitive and must be all small. The following are the built-in functions:

Function Description
cos() Takes a single parameter of a radius angle and returns the "cos" of it.
sin() Takes a single parameter of a radius angle and returns the "sin" of it.
tan() Takes a single parameter of a radius angle and returns the "tan" of it.
cosh() Takes a single parameter of a radius angle and returns the "cosh" of it.
sinh() Takes a single parameter of a radius angle and returns the "sinh" of it.
tanh() Takes a single parameter of a radius angle and returns the "tanh" of it.
ln() Takes a single parameter of a number and returns the "ln" of it, which is the logarithm of base "e".
log() Takes a single parameter of a number and returns the "log" of it, which is the logarithm of base "10".
logn() Takes two parameters; the first is a number that we want to compute the logarithm of; the second parameter is the base of the logarithm.
sqrt() Takes a single parameter number and returns its square root.
abs() Takes a single parameter number and returns its absolute value.
acos() Takes a single parameter number and returns its "arc cos".
asin() Takes a single parameter number and returns its "arc sin".
atan() Takes a single parameter number and returns its "arc tan".
exp() Takes a single parameter number and returns its exponent.

Also, you can define your own functions; those functions can contain from zero to any number of parameters. To define your own functions, you must define a delegate function of the following type: "EvaluateFunctionDelegate". This type is defined in Function.cs; then call the "DefaultFunctionEvaluation" property member to set your delegate function. All the functions that you have defined in the delegate function will be added to the built-in function.

Also, the variable "pi" is internally recognized as 3.14159265358979, and the variable "e" is internally recognized as 2.71828182845905. If any error happens, whatever the error type, the error property will return true and the description of the error will be returned by the ErrorDescription property member.

Here some examples of how to use the Function class:

    //-- Example 1: Simple --
    Function fn = new Function();
    fn.Parse("1+2");
    fn.Infix2Postfix();
    fn.EvaluatePostfix();
    double nResult = fn.Result;

//------------------------------------------------------------

    //-- Example 2: How to use built-in function --
    Function fn = new Function();
    fn.Parse("1+2*5-cos(pi)");
    fn.Infix2Postfix();
    fn.EvaluatePostfix();
    double nResult = fn.Result;

//----------------------------------------------------------------

    //-- Example 3: How to use the variable --
    Function fn = new Function();
    fn.Parse("x+2*y-cos(pi)");
    fn.Infix2Postfix();
    ArrayList var = fn.Variables;
    foreach(Symbol sym in var)
    {
      if(sym..m_name == "x")
         sym.m_value = 1;
      else if(sym..m_name == "y")
              sym.m_value = 5;
             }
    fn.Variables = var;
    fn.EvaluatePostfix();
    double nResult = fn.Result;

//----------------------------------------------------------------

    //-- Example 4: How to use the recursive function call --
    Function fn = new Function();
    fn.Parse("sin(cos(pi)*pi/2)");
    fn.Infix2Postfix();
    fn.EvaluatePostfix();
    double nResult = fn.Result;

//----------------------------------------------------------------

    //-- Example 5: How to extend the built-in existing function
    //   using a delegate --

    //-- Let's say you want to add a function called Add that takes
    //   two numbers and returns the sum of both numbers
    //-- The function will be implemented like that --

    public Symbol EvaluateFnc(string name,params Object[] args)
    {
      Symbol result;
      result.m_name = "";
      result.m_type = EB.Math.Type.Result;
      result.m_value = 0;
      switch(name)
      {
           case "add":
           if(args.Length == 2)
           {
             result.m_name = name + "(" + 
             ((Symbol)args[0]).m_value.ToString() + ")";
                      result.m_value = ((Symbol)args[0]).m_value +
             ((Symbol)args[1]).m_value;
           }
           else
           {
             result.m_name = "Invalid number of parameters in:
                             "+ name +".";
             result.m_type = EB.Math.Type.Error;
           }
           break;
           default:
           {
             result.m_name = "Function: "+ name +", 
                              not found.";
             result.m_type = EB.Math.Type.Error;
           }
           break;
         }
         return result;
       }

    //-- After that, to register this function in the Function
    //   class, do the following:

    Function fn = new Function();
    fn.DefaultFunctionEvaluation = new
EvaluateFunctionDelegate(EvaluateFnc);


//----------------------------------------------------------------

The other part of the program demonstrates how to use the Function class; it also demonstrates how to use DataGrid as a normal grid to show the symbol table without any database connection. To use this program, after compiling the program, write any mathematic expression in the edit box; then click parse. If the expression contains any variable, you can change the value of this variable in the DataGrid Control. After that, click Evaluate to see the result.

N.B.: This class does not handle errors in the expression. This means any error can get through an exception and terminate the program.

Downloads

Download demo project - 13 Kb
Download source - 3 Kb


Comments

  • Great

    Posted by Legacy on 02/21/2004 12:00am

    Originally posted by: Satish

    Great Emad.. ... :) Keep it up....
    Helped me lot in my project.

    Thanks
    Satish

    Reply
  • Some value addition...

    Posted by Legacy on 01/03/2004 12:00am

    Originally posted by: K.G.

    How to add support for operators like ==, >=, <= etc?

    Reply
  • Function Evaluator

    Posted by Legacy on 09/27/2003 12:00am

    Originally posted by: PDJ

    Great work. Helps me a lot !

    Reply
  • Types

    Posted by Legacy on 07/04/2003 12:00am

    Originally posted by: Marco Guimar�es

    Does this support only Integers? I tried to put a double in the expression (5.3 or 3,6) and I can't get the correct result.

    Thanks !

    Reply
  • state variable

    Posted by Legacy on 04/18/2003 12:00am

    Originally posted by: internationale

    what do the states represented by the "state" variable 1, 2, 3 in the parse method signify? If you were to give them descriptive names what would you call them?

    Reply
  • About function with no args

    Posted by Legacy on 04/10/2003 12:00am

    Originally posted by: Liu

    2 + a() will not work, if a() is a function.
    why?

    Reply
  • Logn() in Function Evaluator

    Posted by Legacy on 02/26/2003 12:00am

    Originally posted by: David Keen

    The description of the logn() function is incorrect.

    The first parameter is the base, the second the number whose log is being taken. E.g. logn(10,2) gives 0.3010, logn(10,100) gives 2 exactly.

    So this is not a problem with the function, but with its description in the table.

    David

    Reply
  • sin(pi).... using pi

    Posted by Legacy on 02/14/2003 12:00am

    Originally posted by: omoshima

    Math.Sin(Math.PI) gives 1.22460635382238E-16 which is obviously not correct because we all know that sin(pi) is really 0... I know this is a precision error, but, how could it be handled? anyone have any discussion about it? answers?

    [update]
    I figured it out... I just had to handle the case when the person wanted to do sin(pi)... hehe. eaaaaaaasy.

    [update]
    but, what about multiples of pi? like 2*pi!? blah...

    [update]
    wait, wait... i think if you just mod by pi it'll be fine... YESS!! It worked!!!

    Reply
  • -12+10 doesn't work

    Posted by Legacy on 12/12/2002 12:00am

    Originally posted by: Chepel

    1) unary minus operator has not implemented...
    
    2) no string support...
    3) why not just
    (new CSharpCodeProvider()).CreateCompiler() ?

    Regards!
    =)

    Reply
  • Why not ScriptControl (or VsaEngine)?

    Posted by Legacy on 12/04/2002 12:00am

    Originally posted by: Gene Stolarov

    In the good old times I had to implements scripting (function evaluation) myself not once or twice. Did manual parsers, yacc/lex. But today why won't you use interfaces provided by microsoft? You are locking yourself into the microsoft world by switching to .NET/C#, so why not to use other stuff they give you for free?

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Cisco and Intel have harnessed flash memory technology and truly innovative system software to blast through the boundaries of today's I/O-bound server/storage architectures. See how they are bringing real-time responsiveness to data-intensive applications—for unmatched business advantage. Sponsored by Cisco and Intel® Partnering in Innovation

  • Protecting business operations means shifting the priorities around availability from disaster recovery to business continuity. Enterprises are shifting their focus from recovery from a disaster to preventing the disaster in the first place. With this change in mindset, disaster recovery is no longer the first line of defense; the organizations with a smarter business continuity practice are less impacted when disasters strike. This SmartSelect will provide insight to help guide your enterprise toward better …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds