65.9K
CodeProject is changing. Read more.
Home

Complex Math Parser and Evaluator in VB.NET

Mar 25, 2022

MIT

3 min read

viewsIcon

39355

downloadIcon

2161

Reduces/evaluates a real/complex math expression

Introduction

In many situations, there may be a string containing a math expression, such as "1+2*5" or "(3+i)(3-i)", and there is the need to do the math and calculate the result. Also, in case of a formula like "0.5*x+4", we may need to calculate the result for several different values of x. In those situations, the complex parser presented here may help.

The classes here are a small part -but improved- of my all free and downloadable CAS calculator http://xrjunque.nom.es. One of the goals is that these classes do not rely on other 'external' classes as happens in the CAS calculator.

The Five Classes

  • Class Global10 contains global values like number of decimals, imaginary character (i or j) or CultureInfo.
  • Class Msg10 just contains a few messages to handle possible errors.
  • Class Rational gives a bit more of accuracy in the operations.
  • Class Complex class does the complex math.
  • Class parseComplex is in charge of dividing the input string into tokens and call accordingly to classes Complex or Msg10. Class Complex makes use of class Rational for its Real and Imaginary members. The 'tokenizing' job is done by a Regex pattern.

Tokens

The tokens groups are:

mode <mode>
numbers <num>
operators <op>
logical operators <lop>
functions <fn>
constants <cnt>
variables <var>
any other character <any>
besides end of tokens <end> formed by an escape character Chr(27).

The pattern looks like:

(?i)(?<mode>(&dec(?<dec>\d{1,2})|&(rad|deg|grad|[hobdij])))(?-i)
(?<numop>(?<num>((\d{1,3}((\,\d{3})+(?!\d))(\.[0-9]+)?)|
            [\d]{1}[\.\dA-Fa-f]*)([eE](\s*)[-+]?[0-9]+)?)|
(?<op>[-+*/\^]))|\(|\)|
(?i)(?<fn>logtwo|logten|acosh|acoth|acsch|asech|asinh|atanh|
floor|round|norm|conj|coth|csch|sech|acos|acot|acsc|asec|asin|atan|cosh|sign|sinh|
sqrt|tanh|abs|cos|cot|csc|exp|log|sec|sin|sqr|tan|ln|re|im)(?![a-zA-Z_]+)|
(?<lop>\<\<|\>\>|nand|mod|and|nor|xor|not|or|%|!)(?![a-zA-Z_]+)|
(?<cnt>e|(?i)pi)(?![a-zA-Z_]+)|
(?<vars>[_a-zA-Z]\w*)+|(?<end>\e)+|
(?<any>[^\s←\,\.])+|(?<any>\,|\.)+
</dec>

Pattern for numbers, depending on the Globalization.CultureInfo setting, may swap the dot (NumberFormat.NumberDecimalSeparator) and the comma (NumberFormat.NumberGroupSeparator).

Mode makes possible to enter numbers in hexadecimal, decimal, octal or binary base; along with setting the number of decimals and the imaginary character.

Using the Code

The are two possible ways of instantiation:

    Dim eP As New ParseComplex
    eP.CultureInfo = New Globalization.CultureInfo("fr-FR")
    ...
    Dim eP As New ParseComplex(New Globalization.CultureInfo("es-AR"))
    ...

By default, CultureInfo is set to "en-US".

Evaluation is done by calling one of the two Evaluate() methods.

First method:

    '// argument is a string:
    Dim cplx As Complex = eP.Evaluate("(3+5*i)*(3-i*5)")
    

First method with variables, set in a Dictionay(Of String, Complex):

    eP.vars.Add("x", Complex.one)
    eP.vars.Add("y", New Complex(-1, 2))
    '// argument is a string:
    Dim cplx As Complex = eP.Evaluate("(3+x*i)*(y-i*5)")

Once the string has been parsed, it is possible to call the overloaded second method:

    '// change "x" value (change any variable value):
     eP.vars.Item("x") = New Complex(3)
    '// argument is the Dictionary(Of String, Complex):
    Dim cplx As Complex = eP.Evaluate(eP.vars)
   

Variables names start with a letter or underscore (_), can contain letters, numbers or underscore and can be any length.

Of course, you may call the Complex class directly, if you don't need the parser.

The default numeric base is decimal. To change to another base write &h (hexadecimal), &o (octal) or &b (binary). Appending &d will restore to decimal base.

In a similar way, &deg, &grad will accept angles in degrees or in gradians. To restore to default radians, enter &rad.

To change default imaginary i to j, write &j and to turn back to the default character, write &i.

For instance, entering &culture it-IT will change the current CultureInfo to it-IT. So inputs and ouputs will be in mented culture.

An example of possible modificators is the following:

  Dim cplx As Complex = eP.Evaluate("&culture fr-FR &dec2 &h 0f + &j &d 0,2+0,3*j"
  Console.WriteLine(cplx.tostring) ' will show 15,2+j*0,3

The Output

You may call Complex.ToString() or ToStringComplex( numDecimals As Int32, sImg As String, cultureInfo As Globalization.CultureInfo) As String:

   cplx.ToStringComplex(4, eP.Imaginary, eP.CultureInfo)

Detail Version

If the word detail is found, code will output operation steps. For example:

    Dim cP As New ParseComplex
    Dim cplx As Complex = cP.Evaluate("detail (2+i*3)*(1+i)")
    Console.WriteLine(cP.GetDetail)
    ' Will output:
    ' [ (2+i*3)*(1+i) ]
    ' [2*1 - 3*1 + i*(2*1+3*1) ]
    ' [-1+i*5]

Basic Principles

The parsing method is a recursive-descent parsing: Parsing Expressions by Recursive Descent.

Evaluation method E calls T for any addition or substraction, but T calls first F for any multiplication or substraction, and F calls first P for any power possible power operation. P calls first v to get next token. If there is a "(" token, v calls recursively to T.

    E --> T {( "+" | "-" ) T}
    T --> F {( "*" | "/" ) F}
    F --> P ["^" F]
    P --> v | "(" E ")" | "-" T

Step by Step Walk-throughs

The algorithm presented here englobes T and F in a single method. Besides, method v operates logical operators, '%' and mod any possible function like cos(), csc() and so on.

While writing this article, I found some glitches. If you find any further error, please let me know.

History

  • 25th March, 2022: Initial version