5

Complex Math Parser and Evaluator in VB.NET

 2 years ago
source link: https://www.codeproject.com/Articles/5328357/Complex-Math-Parser-and-Evaluator-in-VB-NET
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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 Four Classes

  • 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:

Copy Code
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:

Copy Code
(?<end>\e)+|
(?<numop>
(?<num>((\d{1,3}((\,\d{3})+(?!\d))(\.[0-9]+)?)|[\.\d]+)([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)|
(?<lop>nand|mod|and|nor|xor|not|or)|
(?<cnt>e|(?i)pi)|
(?<vars>\w+)|
(?<any>[^\s?\,\.])+|(?<any>
\,|\.)+

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

Using the Code

The are two possible ways of instantiation:

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

You may call Complex.ToString() or ToStringComplex(Optional numDecimals As Int32 = 15, Optional sImg As String = "i", Optional cultureInfo As Globalization.CultureInfo = Nothing) As String:

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

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.

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

Step by Step Walk-throughs

Algorithm presented here englobes T, F, and P in a single method. Besides, method v operates 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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK