Home
Search
 
What's New
Index
Books
Links
Q & A
Newsletter
Banners
 
Feedback
Tip Jar
 
C# Helper...
 
XML RSS Feed
Follow VBHelper on Twitter
 
 
 
MSDN Visual Basic Community
 
 
 
 
 
TitleEvaluate mathematical expressions using code in Visual Basic 2005
DescriptionThis example shows how to evaluate mathematical expressions using code in Visual Basic 2005.
Keywordsmathematical expression, expression, evaluate, VB.NET
CategoriesAlgorithms, Strings
 
Find the higher precedence operator in the expression. Break the expression into the operator's operands (for example, in 1 + 3 the operator is + and the operands are 1 and 3). Recursively call the EvaluateExpression function to evaluate the operands and combine the results using the correct Visual Basic operator.

A couple details require some thought. First, keep track of the number of open parentheses. If an operator is inside open parentheses, it does not have the highest precedence.

Second, the code needs to watch for unary operators as in +12 and 13 + -6. Where the function encounters a + or - determines whether it is unary. For example, in 13 + -6 the - is unary but the + is not. Read the code to see how the function handles this.

Note how the program handles the code-defined function Factorial. You can add other functions similarly.

 
Private Enum Precedence
    None = 11
    Unary = 10   ' Not actually used.
    Power = 9
    Times = 8
    Div = 7
    IntDiv = 6
    Modulus = 5
    Plus = 4
End Enum

' Evaluate the expression.
Public Function EvaluateExpression(ByVal expression As _
    String, ByVal primitives As Dictionary(Of String, _
    Double)) As Double
    'Dim expr As String
    'Dim is_unary As Boolean
    'Dim next_unary As Boolean
    'Dim parens As Integer
    'Dim pos As Integer
    'Dim expr_len As Integer
    'Dim ch As String
    'Dim lexpr As String
    'Dim rexpr As String
    'Dim value As String
    'Dim status As Long
    'Dim best_pos As Integer
    'Dim best_prec As Integer

    ' Remove all spaces.
    Dim expr As String = Replace$(expression, " ", "")
    Dim expr_len As Integer = expr.Length
    If expr_len = 0 Then Return 0
    
    ' If we find + or - now, it is a unary operator.
    Dim is_unary As Boolean = True

    ' So far we have nothing.
    Dim best_prec As Precedence = Precedence.None
    Dim best_pos As Integer = 0

    ' Find the operator with the lowest precedence.
    ' Look for places where there are no open
    ' parentheses.
    Dim parens As Integer = 0
    Dim next_unary As Boolean = False
    For pos As Integer = 0 To expr_len - 1
        ' Examine the next character.
        Dim ch As String = expr.Substring(pos, 1)

        ' Assume we will not find an operator. In
        ' that case, the next operator will not
        ' be unary.
        next_unary = False

        If ch = " " Then
            ' Just skip spaces. We keep them here
            ' to make the error messages easier to read.
        ElseIf ch = "(" Then
            ' Increase the open parentheses count.
            parens = parens + 1

            ' A + or - after "(" is unary.
            next_unary = True
        ElseIf ch = ")" Then
            ' Decrease the open parentheses count.
            parens = parens - 1

            ' An operator after ")" is not unary.
            next_unary = False

            ' If parens < 0, too many ')'s.
            If parens < 0 Then
                Throw New NotSupportedException("Too many " & _
                    ")s in expression '" & expression & "'")
            End If
        ElseIf parens = 0 Then
            ' See if this is an operator.
            If ch = "^" Or ch = "*" Or _
               ch = "/" Or ch = "\" Or _
               ch = "%" Or ch = "+" Or _
               ch = "-" _
            Then
                ' An operator after an operator
                ' is unary.
                next_unary = True

                ' See if this operator has higher
                ' precedence than the current one.
                Select Case ch
                    Case "^"
                        If best_prec >= Precedence.Power _
                            Then
                            best_prec = Precedence.Power
                            best_pos = pos
                        End If

                    Case "*", "/"
                        If best_prec >= Precedence.Times _
                            Then
                            best_prec = Precedence.Times
                            best_pos = pos
                        End If

                    Case "\"
                        If best_prec >= Precedence.IntDiv _
                            Then
                            best_prec = Precedence.IntDiv
                            best_pos = pos
                        End If

                    Case "%"
                        If best_prec >= Precedence.Modulus _
                            Then
                            best_prec = Precedence.Modulus
                            best_pos = pos
                        End If

                    Case "+", "-"
                        ' Ignore unary operators
                        ' for now.
                        If (Not is_unary) And _
                            best_prec >= Precedence.Plus _
                        Then
                            best_prec = Precedence.Plus
                            best_pos = pos
                        End If
                End Select
            End If
        End If
        is_unary = next_unary
    Next pos

    ' If the parentheses count is not zero,
    ' there's a ')' missing.
    If parens <> 0 Then
        Throw New NotSupportedException("Missing ) in " & _
            "expression '" & expression & "'")
    End If

    ' Hopefully we have the operator.
    If best_prec < Precedence.None Then
        Dim lexpr As String = expr.Substring(0, best_pos)
        Dim rexpr As String = expr.Substring(best_pos + 1)
        Select Case expr.Substring(best_pos, 1)
            Case "^"
                Return _
                    EvaluateExpression(lexpr, primitives) ^ _
                        _
                    EvaluateExpression(rexpr, primitives)
            Case "*"
                Return _
                    EvaluateExpression(lexpr, primitives) * _
                        _
                    EvaluateExpression(rexpr, primitives)
            Case "/"
                Return _
                    EvaluateExpression(lexpr, primitives) / _
                        _
                    EvaluateExpression(rexpr, primitives)
            Case "\"
                Return _
                    EvaluateExpression(lexpr, primitives) \ _
                        _
                    EvaluateExpression(rexpr, primitives)
            Case "%"
                Return _
                    EvaluateExpression(lexpr, primitives) _
                        Mod _
                    EvaluateExpression(rexpr, primitives)
            Case "+"
                Return _
                    EvaluateExpression(lexpr, primitives) + _
                        _
                    EvaluateExpression(rexpr, primitives)
            Case "-"
                Return _
                    EvaluateExpression(lexpr, primitives) - _
                        _
                    EvaluateExpression(rexpr, primitives)
            Case Else ' This shouldn't happen.
                Throw New NotSupportedException("Error " & _
                    "evaluating expression '" & expression _
                    & "'")
        End Select
    End If

    ' If we do not yet have an operator, there
    ' are several possibilities:
    '
    ' 1. expr is (expr2) for some expr2.
    ' 2. expr is -expr2 or +expr2 for some expr2.
    ' 3. expr is Fun(expr2) for a function Fun.
    ' 4. expr is a primitive.
    ' 5. It's a literal like "3.14159".

    ' Look for (expr2).
    If expr.StartsWith("(") And expr.EndsWith(")") Then
        ' Remove the parentheses.
        Return EvaluateExpression( _
            expr.Substring(1, expr_len - 2), _
            primitives)
    End If

    ' Look for -expr2.
    If expr.StartsWith("-") Then
        Return -EvaluateExpression( _
            expr.Substring(1), _
            primitives)
    End If

    ' Look for +expr2.
    If expr.StartsWith("+") Then
        Return EvaluateExpression( _
            expr.Substring(1), _
            primitives)
    End If

    ' Look for Fun(expr2).
    If expr_len > 5 And expr.EndsWith(")") Then
        ' Find the first (.
        Dim pos As Integer = expr.IndexOf("(")

        If pos > 0 Then
            ' See what the function is.
            Dim lexpr As String = expr.Substring(0, _
                pos).ToLower()
            Dim rexpr As String = expr.Substring(pos + 1, _
                expr_len - pos - 2)
            Select Case lexpr
                Case "sin"
                    Return Math.Sin(EvaluateExpression(rexpr, _
                        primitives))
                Case "cos"
                    Return Math.Cos(EvaluateExpression(rexpr, _
                        primitives))
                Case "tan"
                    Return Math.Tan(EvaluateExpression(rexpr, _
                        primitives))
                Case "sqrt"
                    Return Math.Sqrt(EvaluateExpression(rexpr, _
                        primitives))
                Case "factorial"
                    Return Factorial(EvaluateExpression(rexpr, _
                        primitives))

                    ' Add other functions (including
                    ' program-defined functions) here.
            End Select
        End If
    End If

    ' See if it's a primitive.
    If primitives.ContainsKey(expr) Then
        ' We found the primative.
        Return CDbl(primitives(expr))
    End If

    ' It must be a literal like "2.71828".
    ' Try to return it and let any errors throw.
    Return CDbl(expr)
End Function

' Return the factorial of the expression.
Private Function Factorial(ByVal value As Integer) As Double
    Dim result As Double = 1
    Do While value > 1
        result *= value
        value -= 1
    Loop
    Return result
End Function
 
 
Copyright © 1997-2010 Rocky Mountain Computer Consulting, Inc.   All rights reserved.
  Updated