# Function Evaluator

**Emad Barsoum**on

**December 4th, 2002**

__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 KbDownload source - 3 Kb