Click here to Skip to main content
11,720,364 members (71,657 online)
Click here to Skip to main content

Evaluating Mathematical Expressions by Compiling C# Code at Runtime

, 21 Apr 2003 183.3K 80
Rate this:
Please Sign up or sign in to vote.
A completely new way of making a mathematical expression evaluator.

Introduction

There are many articles on creating mathematical expression parsers (i.e. for displaying 3D functions where user inputs the formulas manually). Most of them are based on lexical analysis, grammar definitions etc. With C# there is a solution for making mathematical expression evaluator in a completely new way: by compiling code at runtime.

Let's assume that we want to create an application that would calculate 3D function like that:

z = f(x,y)

But we want to let the user input function formula manually (we don't know what the formula will look like).

A solution to deal with that task in 10 minutes is:

  1. Let the user input the function
  2. Compile that function into memory
  3. Run the function with given x and y
  4. Do something with result z value


To do that in a couple of minutes we would need a class with virtual method:

namespace MathEval<BR>{<BR> public class MyClassBase<BR> {<BR>  public MyClassBase()<BR>  {<BR>  }<BR>  public virtual double eval(double x,double y)<BR>  {<BR>   return 0.0;<BR>  }<BR> }<BR>}<BR>

all we need more is a parser/evaluator class which would compile function body into assembly (created in memory) and calculate function result:

<BR>using System;<BR>using System.Reflection;<BR>using System.Windows.Forms;<BR>namespace MathEval<BR>{<BR> public class MathExpressionParser<BR> {<BR>  MyClassBase myobj = null;<BR>  public MathExpressionParser()<BR>  {<BR>  }<BR>  public bool init(string expr)<BR>  {<BR>   Microsoft.CSharp.CSharpCodeProvider cp<BR>                                = new Microsoft.CSharp.CSharpCodeProvider();<BR>   System.CodeDom.Compiler.ICodeCompiler ic = cp.CreateCompiler();<BR>   System.CodeDom.Compiler.CompilerParameters cpar<BR>                         = new System.CodeDom.Compiler.CompilerParameters();<BR>   cpar.GenerateInMemory = true;<BR>   cpar.GenerateExecutable = false;<BR>   cpar.ReferencedAssemblies.Add("system.dll");<BR>   cpar.ReferencedAssemblies.Add("matheval.exe"); <BR>   string src = "using System;"+<BR>    "class myclass:MathEval.MyClassBase" + <BR>    "{"+<BR>    "public myclass(){}"+<BR>    "public override double eval(double x,double y)"+<BR>    "{"+<BR>    "return "+ expr +";"+<BR>    "}"+<BR>    "}";<BR>   System.CodeDom.Compiler.CompilerResults cr<BR>                                   = ic.CompileAssemblyFromSource(cpar,src);<BR>   foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors)<BR>    MessageBox.Show(ce.ErrorText); <BR><BR>   if (cr.Errors.Count == 0 && cr.CompiledAssembly != null)<BR>   {<BR>    Type ObjType = cr.CompiledAssembly.GetType("myclass");<BR>    try<BR>    {<BR>     if (ObjType != null)<BR>     {<BR>      myobj = (MyClassBase)Activator.CreateInstance(ObjType);<BR>     }<BR>    }<BR>    catch (Exception ex)<BR>    {<BR>     MessageBox.Show(ex.Message);<BR>    }<BR>    return true;<BR>   }<BR>   else <BR>    return false;<BR>  }<BR>  public double eval(double x,double y)<BR>  {<BR>   double val = 0.0;<BR>   if (myobj != null)<BR>   {<BR>     val = myobj.eval(x,y);<BR>   }<BR>   return val;<BR>  }<BR> }<BR>}<BR>

Take a look at the init() method. All we need it to do is to create an assembly(in memory) with a class "myclass" derived from MyBaseClass. Note that "eval" method contains the formula given by the user at runtime. Also note that cpar.ReferencedAssemblies.Add("matheval.exe"); defines a reference to the application currently being created.
Then we can call myclass.eval method as many times as we want to:

<BR>MathExpressionParser mp = new MathExpressionParser();<BR>mp.init("Math.Sin(x)*y");<BR><BR><BR>for(int i=0;i<1000000;i++)<BR>{<BR> mp.eval((double)i,(double)i);<BR>}<BR>

Compiled code is of course much faster than any other solution used to parse and evaluate expressions.

A few things to do:

  • Let the user input formulas as "xy*sin(x+y)" or "x^2+y^2" and convert them to c# "x*y*Math.Sin(x+y)" "x*x + y*y" etc...
  • Do some error checking/handling other than compiler errors.
  • Freeing and recreating the in-memory-assembly with another formula.
  • Enjoy the code Smile | :)

PS: special thanks to AcidRain for some ideas Smile | :)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Marcin Cuprjak
Architect
Poland Poland
No Biography provided

You may also be interested in...

Comments and Discussions

 
QuestionCompile function in memory in objective-c for mac Pin
wonkypuh1018-Jun-11 12:17
memberwonkypuh1018-Jun-11 12:17 
QuestionCompletely New? Pin
Dewey21-Jan-08 14:28
memberDewey21-Jan-08 14:28 
AnswerRe: Completely New? Pin
Marcin Cuprjak (aka Vlad Tepes)23-Jan-08 9:33
memberMarcin Cuprjak (aka Vlad Tepes)23-Jan-08 9:33 
QuestionWhat is wrong with double FuncN (params double[] x) ? Pin
hreba22-Nov-06 3:40
memberhreba22-Nov-06 3:40 
GeneralGood Work! Pin
gajatko3-Oct-06 2:17
membergajatko3-Oct-06 2:17 
GeneralNot applicable for ASP.NET2 applications Pin
ZuZuKin23-Feb-06 9:10
memberZuZuKin23-Feb-06 9:10 
GeneralVery Nice Pin
msaroka20-Apr-05 12:48
membermsaroka20-Apr-05 12:48 
General&quot;matheval.exe&quot; Pin
xorenko17-Apr-05 0:11
memberxorenko17-Apr-05 0:11 
GeneralExtremely insecure! Pin
ekolis14-Jun-04 15:59
memberekolis14-Jun-04 15:59 
QuestionHow to unload an assembly? Pin
Heng Ma30-Jul-03 10:48
memberHeng Ma30-Jul-03 10:48 
AnswerRe: How to unload an assembly? Pin
tuxic7-Mar-05 9:01
membertuxic7-Mar-05 9:01 
QuestionWhat about Microsoft.JScript.Eval()? Pin
onc29-Apr-03 3:59
memberonc29-Apr-03 3:59 
GeneralGenerate IL directly Pin
hsauro22-Apr-03 19:48
memberhsauro22-Apr-03 19:48 
GeneralRe: Generate IL directly Pin
leppie23-Apr-03 7:02
memberleppie23-Apr-03 7:02 
GeneralRe: Generate IL directly Pin
Kris Vandermotten29-Apr-03 4:25
sussKris Vandermotten29-Apr-03 4:25 
Generating IL directly has many advantages.

Of course, what you are really doing is writing a compiler for your own expression language. This article basically suggests the alternative of not writing your own compiler, but using the C# one. Consider this approach as being "quick and dirty", but it works.

Anyway, if you want to know about IL generation, have a look at the excellent paper at http://www.dina.dk/~sestoft/rtcg/rtcg.pdf . This paper discusses runtime code generation in a partial evaluation context, as an optimization technique. It also lists benchmark results.
GeneralCompiling In Memory Pin
Blake Coverett22-Apr-03 16:26
memberBlake Coverett22-Apr-03 16:26 
GeneralRe: Compiling In Memory Pin
Jonathan de Halleux22-Apr-03 23:02
memberJonathan de Halleux22-Apr-03 23:02 
GeneralRe: Compiling In Memory Pin
Rama Krishna23-Apr-03 3:12
memberRama Krishna23-Apr-03 3:12 
GeneralRe: Compiling In Memory Pin
leppie23-Apr-03 7:00
memberleppie23-Apr-03 7:00 
GeneralRe: Compiling In Memory Pin
Rama Krishna23-Apr-03 7:06
memberRama Krishna23-Apr-03 7:06 
GeneralRe: Compiling In Memory Pin
Blake Coverett23-Apr-03 16:48
memberBlake Coverett23-Apr-03 16:48 
GeneralRe: Compiling In Memory Pin
Rama Krishna24-Apr-03 1:46
memberRama Krishna24-Apr-03 1:46 
GeneralRe: Compiling In Memory Pin
Blake Coverett24-Apr-03 13:41
memberBlake Coverett24-Apr-03 13:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150901.1 | Last Updated 22 Apr 2003
Article Copyright 2003 by Marcin Cuprjak
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid