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

Complex Math Parser and Evaluator in VB.NET

5.00/5 (15 votes)
15 Aug 2023MIT3 min read 39.4K   2.2K  
Reduces/evaluates a real/complex math expression
The code consists of four classes in order to evaluate a string of a real or complex math expression, reducing the expression to one real or complex number. The math expression may or may not include variables.

Image 1

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:

VB.NET
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:

VB.NET
'// 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):

VB.NET
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:

VB.NET
'// 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.

Image 2

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:

VB.NET
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:

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

Detail Version

Image 3

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

VB.NET
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

License

This article, along with any associated source code and files, is licensed under The MIT License