Is there a string math evaluator in .NET?

Viewed 81866

If I have a string with a valid math expression such as:

String s = "1 + 2 * 7";

Is there a built in library/function in .NET that will parse and evaluate that expression for me and return the result? In this case 15.

18 Answers

You could add a reference to Microsoft Script Control Library (COM) and use code like this to evaluate an expression. (Also works for JScript.)

Dim sc As New MSScriptControl.ScriptControl()
sc.Language = "VBScript"
Dim expression As String = "1 + 2 * 7"
Dim result As Double = sc.Eval(expression)

Edit - C# version.

MSScriptControl.ScriptControl sc = new MSScriptControl.ScriptControl();
sc.Language = "VBScript";
string expression = "1 + 2 * 7";
object result = sc.Eval(expression);            
MessageBox.Show(result.ToString());

Edit - The ScriptControl is a COM object. In the "Add reference" dialog of the project select the "COM" tab and scroll down to "Microsoft Script Control 1.0" and select ok.

For anybody developing in C# on Silverlight here's a pretty neat trick that I've just discovered that allows evaluation of an expression by calling out to the Javascript engine:

double result = (double) HtmlPage.Window.Eval("15 + 35");

Actually there is kind of a built in one - you can use the XPath namespace! Although it requires that you reformat the string to confirm with XPath notation. I've used a method like this to handle simple expressions:

    public static double Evaluate(string expression)
    {
        var xsltExpression = 
            string.Format("number({0})", 
                new Regex(@"([\+\-\*])").Replace(expression, " ${1} ")
                                        .Replace("/", " div ")
                                        .Replace("%", " mod "));

        return (double)new XPathDocument
            (new StringReader("<r/>"))
                .CreateNavigator()
                .Evaluate(xsltExpression);
    }

You can use Math-Expression-Evaluator library that I am author of. It supports simple expressions such as 2.5+5.9, 17.89-2.47+7.16, 5/2/2+1.5*3+4.58, expressions with parentheses (((9-6/2)*2-4)/2-6-1)/(2+24/(2+4)) and expressions with variables:

var a = 6;
var b = 4.32m;
var c = 24.15m;
var engine = new ExpressionEvaluator();
engine.Evaluate("(((9-a/2)*2-b)/2-a-1)/(2+c/(2+4))", new { a, b, c});

You can also pass parameters as named variables:

dynamic dynamicEngine = new ExpressionEvaluator();

var a = 6;
var b = 4.5m;
var c = 2.6m;

dynamicEngine.Evaluate("(c+b)*a", a: 6, b: 4.5, c: 2.6);

It supports .Net Standard 2.0 so can be used from .Net Core as well as .Net Full Framework projects and it doesn't have any external dependencies.

There's no built-in solution, but there are easy ways to make it work.

There are at least two good new solutions for the problem now: using symbolic algebra AngouriMath or general purpose algorithm library Towel.

AngouriMath

You can do

using AngouriMath;
Entity expr = "1 + 2 + sqrt(2)";
var answer = (double)expr.EvalNumerical();

(by default it computes in high-precision, might be useful too)

Or compile it

Entity expr = "1 + 2 + sqrt(2) + x + y";
Func<double, double, double> someFunc = expr.Compile<double, double, double>("x", "y");
Console.WriteLine(someFunc(3, 5));

so that it could be used in time-critical code.

Towel

Here you can do

using Towel.Mathematics;
var expression = Symbolics.Parse<double>("(2 + 2 * 2 - (2 ^ 4)) / 2");
Console.WriteLine(expression.Simplify());

which would directly compute your expression into double.

Installation

Both can be installed via Nuget: AngouriMath, Towel.

MathNet.Symbolics

using System;
using static MathNet.Symbolics.SymbolicExpression;
using static System.Console;
using static System.Numerics.Complex;
using Complex = System.Numerics.Complex;

namespace MathEvaluator
{
    class Program
    {
        static readonly Complex i = ImaginaryOne;

        static void Main(string[] args)
        {
            var z = Variable("z");
            Func<Complex, Complex> f = Parse("z * z").CompileComplex(nameof(z));
            Complex c = 1 / 2 - i / 3;
            WriteLine(f(c));


            var x = Variable("x");
            Func<double, double> g = Parse("x * x + 5 * x + 6").Compile(nameof(x));
            double a = 1 / 3.0;
            WriteLine(g(a));
        }
    }
}

Don't forget to load

<PackageReference Include="MathNet.Symbolics" Version="0.20.0" />
Related