Parsing a math expression from string in C#

WhiteBlackGoose
3 min readJun 18, 2021

--

It’s an old question, which has been asked numerous times on websites like StackOverflow and others. But people still see 5–10 year old answers and articles which recommend terrible creating DataTable and evaluating expressions there instead of using specific tools suited exactly for this problem.

Parsing a math expression… is not only about parsing, but also about math, so I’ll show how we can do that with a math library AngouriMath (and show a few other solutions in the end of the article).

Installation

First, install it from NuGet. You can do it in Visual Studio:

OR by typing this in the folder with your project

dotnet add package AngouriMath --prerelease

OR you can also insert this

<ItemGroup>
<PackageReference Include="AngouriMath" Version="1.3.0-preview.4" />
</ItemGroup>

into your project file (csproj). Just make sure to install the latest relevant version.

Parsing and evaluating

Now we can get to the code. Import namespaces that we will need:

using AngouriMath;
using AngouriMath.Extensions;

Now we can finally parse an expression in three ways, we will consider only one.

Entity expr = "2 / 5 + 6";

Now, expr is a math expression which is a sum of a fraction and 6. We can print it out:

Entity expr = "2 / 5 + 6";
Console.WriteLine(expr.EvalNumerical());

It will output 32/5 because .EvalNumerical() computes an expression into an integer, rational, real or complex. If you unconditionally need to get a decimal representation, you can cast it into one of primitive types, for example, double or decimal:

Entity expr = "2 / 5 + 6";
Console.WriteLine((decimal)expr.EvalNumerical());
Console.WriteLine((double)expr.EvalNumerical());
Console.WriteLine((int)expr.EvalNumerical());

The output is

6.4
6.4
6

More advanced usage

The default precision is much higher than that of built-in types, for example that’s what square root of 2 looks like:

Entity expr = "sqrt(2)";
Console.WriteLine(expr.EvalNumerical());

Output:

1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573

You can also substitute variables in an expression. Skipping simple usages, you can compile them into functions:

Entity expr = "hypotenuse * sin(theta)";
var cathetus = expr.Compile<double, double, double>("hypotenuse", "theta");
Console.WriteLine(cathetus(5, Math.PI / 6));

cathetus is of type Func<double, double, double> which takes a length of hypotenuse and theta and computes a cathetus. Now it can be used in performance-critical places, because it is as fast as if you wrote that function as a separate method using built-in math functions.

Other solutions

There is an awesome project dotnet/interactive, which allows us to run C# and F# interactively not only in a separate console, but also in Jupyter, VSC, and finally right from code using embedded kernels. There is a simple example (permalink to the code) which demonstrates how to evaluate arbitrary C# code.

There is also a general-purpose algorithm library Towel, which also can parse and evaluate math expressions.

References

AngouriMath: github, website, playground

Dotnet/Interactive: github, playground

Towel: github

All mentioned projects are open source and free to use. In case of questions, I recommend opening an issue on github pages of the project you’re having troubles with (or joining their chat, if available).

The first picture was taken from Jupyter with F# and AngouriMath.Interactive, you can read about it here.

Thanks for your attention!

--

--

WhiteBlackGoose
WhiteBlackGoose

No responses yet