Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

Math Expression Evaluator

2.90/5 (4 votes)
18 Aug 2006CPOL1 min read 1   433  
Calculate the result of a math expression.

Sample screenshot

Introduction

This is another math expression evaluator with which you can let the user type an expression in text format with up to three variables (x, y, z) and calculate the result according to the variable values.

The main idea

Parse the text function and build a tree-like structure because a math expression is always an operator with "something" left and "something" right. "something" can be a variable or a number or an expression itself. Functions like sin, cos... are special nodes whose argument is an expression. Simple, isn't it?

For example: 2*x - 4/sin(3*x) according to the operator precedence is a subtraction, if we build a tree like this...

                  -----
                 |  -  |
                  -----
          _______|  |  |_______
         |        -----        |
       -----                 -----
      |  *  |               |  /  |
       -----                 -----
     _|  |  |_             _|  |  |_
    |  -----  |           |  -----  |
  -----     -----       -----     -----
 |  2  |   |  X  |     |  4  |   | sin |
 | nr. |   | var |     | nr. |   |-----|
  -----     -----       -----    |     |
                                  --|--
                                    |
                                  -----
                                 |  *  |
                                  -----
                                _|  |  |_
                               |  -----  |
                             -----     ----- 
                            |  3  |   |  X  |
                            | nr. |   | var |
                             -----     -----

... we can read the original expression by scanning the tree from left to right.

Building the tree

Each type of node (operator, operand, function) is implemented by a proper class.

VB
Private Class clsFunction
    Protected mName As String
    Protected mArgument As Object
    Public Sub New()
        mName = ""
        mArgument = Nothing
    End Sub
    Property Name() As String
        Get
            Return mName
        End Get
        Set(ByVal Value As String)
            mName = Value
        End Set
    End Property
    Property Argument() As Object
        Get
            Return mArgument
        End Get
        Set(ByVal Value As Object)
            mArgument = Value
        End Set
    End Property
End Class

Private Class clsOperator
    Protected mOperator As String
    Protected mLeft As Object
    Protected mRight As Object
    Public Sub New()
        mLeft = Nothing
        mRight = Nothing
    End Sub
    Property Operator() As String
        Get
            Return mOperator
        End Get
        Set(ByVal Value As String)
            mOperator = Value
        End Set
    End Property
    Property Left() As Object
        Get
            Return mLeft
        End Get
        Set(ByVal Value As Object)
            mLeft = Value
        End Set
    End Property
    Property Right() As Object
        Get
            Return mRight
        End Get
        Set(ByVal Value As Object)
            mRight = Value
        End Set
    End Property
End Class

Private Class clsOperand
    Protected mIsVariable As Boolean
    Protected mVariable As String
    Protected mOperand As Decimal
    Property IsVariable() As Boolean
        Get
            Return mIsVariable
        End Get
        Set(ByVal Value As Boolean)
            mIsVariable = Value
        End Set
    End Property
    Property Variable() As String
        Get
            Return mVariable
        End Get
        Set(ByVal Value As String)
            mVariable = Value
        End Set
    End Property
    Property Operand() As Decimal
        Get
            Return mOperand
        End Get
        Set(ByVal Value As Decimal)
            mOperand = Value
        End Set
    End Property
End Class

We build the expression tree according to the operator precedence this way:

  • Function Expression handles left sum|sub right by calling the function Term for each side.
    • Function Term handles left mult|div right by calling the function Factor for each side.
      • Function Factor handles left power right by calling the function Power for each side.
        • Function Power ends the work by detecting a new expression (if brackets), function (3 letters), variable, or number.

Calculate the result

Once we have the tree, scanning it from left to right to calculate the result is quite simple:

VB
Protected Overridable Function GetResult(ByVal objNode As Object) As Decimal
    'calculate the result of the function in terms of x,y,z
    'by recursively scanning the tree from left to right

    If objNode Is Nothing Then Return 0

    If TypeOf objNode Is clsFunction Then
        Select Case objNode.Name.ToLower
            Case "sin"
                Return System.Math.Sin(GetResult(objNode.Argument))
            Case "cos"
                Return System.Math.Cos(GetResult(objNode.Argument))
            Case "tan"
                Return System.Math.Tan(GetResult(objNode.Argument))
            Case "atn"
                Return System.Math.Atan(GetResult(objNode.Argument))
            Case "lne"
                Return System.Math.Log(GetResult(objNode.Argument))
            Case "log"
                Return System.Math.Log10(GetResult(objNode.Argument))
            Case "sqr"
                Return System.Math.Sqrt(GetResult(objNode.Argument))
        End Select
    ElseIf TypeOf objNode Is clsOperator Then
        Select Case objNode.operator
            Case "+"
                Return GetResult(objNode.Left) + GetResult(objNode.Right)
            Case "-"
                Return GetResult(objNode.Left) - GetResult(objNode.Right)
            Case "*"
                Return GetResult(objNode.Left) * GetResult(objNode.Right)
            Case "/"
                Return GetResult(objNode.Left) / GetResult(objNode.Right)
            Case "^"
                Return GetResult(objNode.Left) ^ GetResult(objNode.Right)
        End Select
    ElseIf objNode.isvariable Then
        Select Case objNode.variable
            Case "X"
                Return mX
            Case "Y"
                Return mY
            Case "Z"
                Return mZ
        End Select
    Else
        Return objNode.operand
    End If
End Function

See the source code for more comments.

Using the code

VB
dim LtFn as New LTFunctions.Functions
With LtFn
   .Function = "sin(x)+2*p" 
   .X =-1 
   .Y = 0
   .Z = 0
   Messagebox.Show (Format(.Result, "standard"))
End With

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)