Click here to Skip to main content
12,077,333 members (46,029 online)
Click here to Skip to main content
Add your own
alternative version


135 bookmarked

Math Parser .NET

, 30 Oct 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
A very easy to use mathematical parser library for .NET.


A while back, I wrote an article on CodeProject called TokenIcer. TokenIcer was a program that would automatically create a lexical parser in either C# or VB.NET, based on RegEx rules created in the program.

Since the time that I wrote the article, I have gotten some very good feedback and I wanted to take it a step further. I decided to use TokenIcer to create a mathematical equation parser. That math parser is presented here in this article and it is called Math Parser .NET. It is a .NET Class Library project that can be used with your own programs.


There are several math parsers that exist already. The goal of my math parser is to keep it as simple to use and operate as possible. One of my biggest pet peeves is when a good library goes "bad" because its simplicity gets overshadowed by its own feature list. I feel that my math parser does its job well while keeping the basic functionality and usage simple.

Using the Code

Before I go into how to use the library, I would like to first go through how the internals of the library work. The library itself first consists of a lexical analyzer. The lexical analyzer, I created automatically, by using TokenIcer. The lexical analyzer will take an input string like this:

1 + 2 * 3 + (9 / 3) 

and convert it into enumerated tokens, like this:


Once there are no more tokens to process, the lexical analyzer will return a null token.

The next job is to create a loop to cycle through each token until the null token is received. The input received by the parser will be in what's called Infix notation. Infix notation means that numbers are separated by mathematical operators. Like the example above, 1 and 2 is separated by a plus sign. 2 and 3 is separated by a multiplication sign. In addition, math operators have a specific order of precedence. In the example above, 9 / 3 should be evaluated first since it is in parenthesis. 2 * 3 should be evaluated secondly since multiplication and division have higher precedence than addition. In order to more easily parse math expressions, I convert the equation from Infix notation to Reverse Polish Notation. In Reverse Polish Notation, or RPN, the math symbols come after the numbers. So after the conversion, the example input above would look similar to this:

1 2 3 * 9 3 / + +

Once the equation is in RPN notation, it is a simple matter of reading it left to right and doing the actual math.

To use the MathNetLib library in your own program, all you have to do is add a reference to the MathNetLib DLL file. After doing that, you need to instantiate a new instance of the MathNetLib.Parser class. There are three main methods for solving equations. The first is called SimplifyInt(). SimplifyInt() will take a mathematical equation, solve it, and return an integer answer. There are two overloads to this method. Here is the first and easiest example:

static void Main()
    MathParserNet.Parser parser = new MathParserNet.Parser();
    int retval;

    try {
        retval = parser.SimplifyInt("3.2 + 7.6");
    } catch (Exception ex) {
        throw ex;

This example will return a value of 11. The thing to keep in mind about SimplifyInt() is that it will always return an integer answer and by default, it will round the answer. SimplifyInt() has an overloaded method signature that will also allow you to specify what you want to do with the fractional part of the answer, if there is one. Here is an example:

static void Main()
    MathParserNet.Parser parser = new MathParserNet.Parser();
    int retval;

    try {
        retval = parser.SimplifyInt("3.2 + 7.6", 
    } catch (Exception ex) {
        throw ex;

RoundingMethods is an enum with the following values and descriptions:

  • Round -- This is the default. Rounds the fraction to the nearest whole number. If the number after the decimal point is a 5 or higher, it will round the whole number up. If it is 4 or lower, it will round the whole number down.
  • RoundDown -- This will always round the whole number down regardless of the number after the decimal point.
  • RoundUp -- This will always round the whole number up regardless of the number after the decimal point.
  • Truncate -- This will not do any rounding at all and will simply "cut off" the decimal point and any numbers after it.

The second main method for solving equations is called SimplifyDouble(). This method, like SimplifyInt(), will solve the equation, but will always return a double answer. Here is an example of this method in action:

static void Main()
    MathParserNet.Parser parser = new MathParserNet.Parser();
    double retval;

    try {
        retval = parser.SimplifyDouble("3.2 + 7.6");
    } catch (Exception ex) {
        throw ex;

This would return an answer of 10.8.

The third and final version for solving math equations is called, simply, Simplify(). Simplify() will solve an equation and then automatically determine if it is an integer or a floating point answer. Simplify() returns a MathParserNet.SimplificationReturnValue object. You can check the ReturnType property of this object to determine if the answer is a floating point or a whole integer number. Here is an example of its use:

static void Main()
    MathParserNet.Parser parser = new MathParserNet.Parser();
    MathParserNet.SimplificationReturnValue retval;

    try {
        retval = parser.Simplify("3.2 + 7.2");
    } catch (Exception ex)
        throw ex;
    if (retval.ReturnType == MathParserNet.SimplificationReturnValue.ReturnTypes.Float)
        Console.WriteLine("The answer is a Floating point number!");
    if (retval.ReturnType == MathParserNet.SimplificationReturnValue.ReturnTypes.Integer)
        Console.WriteLine("The answer is an Integer!");

Anytime you use any of the simplify functions, you should always wrap it in a try/catch block. MathParserNet implements five exceptions. Here is a description of each one:

  • MismatchedParenthesisException -- This exception is thrown if the equation you are trying to solve has more opening parenthesis than closing parenthesis or vice versa.
  • NoSuchFunctionException -- This exception is thrown if you try to use a function that has not yet been defined. Functions are described below.
  • NoSuchVariableException -- This exception is thrown if you try to use a variable that has not yet been defined. Variables are described below.
  • VariableAlreadyDefinedException -- This exception is thrown if you try to define a variable that has already been defined earlier. Variables are described below.
  • CouldNotParseExpressionException -- This exception is thrown if any other problem arises while trying to parse your expression. Passing an empty equation to any of the simplify functions will cause this exception to be raised.

The parser can parse the following things:

  • () -- Parenthesis
  • + -- Add symbol (3 + 2)
  • - -- Subtract symbol (3 - 2)
  • * -- Multiplication symbol (3 * 2)
  • / -- Divide symbol (3 / 2)
  • % -- Modulus symbol (3 % 2)(divides the two numbers, but returns the remainder)
  • ^ -- Exponent symbol (3 ^ 2)(squares 3)
  • ABS -- Function returns the absolute of a number (ABS(-3))
  • SIN -- Returns the sine of a number (SIN(3.14))
  • COS -- Returns the cosine of a number (COS(3.14))
  • TAN -- Returns the tangent of a number (TAN(3.14))
  • LOG -- Returns the base 10 logarithm of a number
  • LOGN -- Returns the natural logarithm of a number
  • func<name> -- Calls a user defined function (see Functions below)


MathParserNet supports the use of variables. You define a variable in MathParserNet using the AddVariable() method. Here is an example of adding three variables to the parser:

static void Main()
    MathParserNet.Parser parser = new MathParserNet.Parser();

    try {
        parser.AddVariable("PI", 3.14159265);
        parser.AddVariable("Three", 3);
        parser.AddVariable("HalfPI", "PI / 2");

        parser.SimplifyDouble("HalfPI * Three + 7");
    } catch (Exception ex) {
        throw ex;

Variables are kind of like cut and paste in a word processor. When the parser sees a variable, it looks up the value and replaces the variable name with the actual value. So HalfPI actually becomes "3.14159265 / 2" and the equation passed into the SimplifyDouble() method actually becomes "3.14159265 / 3 + 7".

Variables that have been defined can also be removed by calling the RemoveVariable() method. You simply pass the variable name as an argument to RemoveVariable() and the variable gets removed. Keep in mind that any variable that has been defined with a removed variable becomes invalid. For example, in the code above, if I remove the PI variable, then the HalfPI variable also becomes invalid. In addition, you can also remove all variables created by calling the RemoveAllVariables() method.

Another thing to keep in mind is that variable names are case-sensitive. PI is different from Pi or pI or pi.


In addition to variables, MathParserNet also supports functions. You can define a function to do pretty much anything you want. Here is an example:

static void Main()
    MathParserNet.Parser parser = new MathParserNet.Parser();

    try {
          new MathParserNet.FunctionArgumentList {"x1", "x2", 
          "y1", "y2"}, "(y1-y2)/(x1-x2)");

        parser.SimplifyDouble("3 * funcGetSlope(3.2 * (9/3), 4.5, 6, 9.2)");
    } catch (Exception ex) {
        throw ex;

This example creates a function called GetSlope. The function takes four parameters (x1,x2,y1,y2). Functions must take at least one parameter and can be defined to take as many as you want. Keep in mind though that function parameter names can not have the same name as a defined variable. To call a function, you must prefix the function name with "func" (without quotes, of course). Another thing to keep in mind is that, like variables, functions are also case-sensitive (as is the "func" prefix).

Functions, just like variables, can similarly be undefined by calling the RemoveFunction() method. As with variables, you simply pass the function name in as a parameter of RemoveFunction(). In addition, you can remove all functions created by calling the RemoveAllFunctions() method.

Delegate Functions

Perhaps the coolest, and arguably, the most handy feature of MathParserNet is the ability to create your own custom function in any .NET language and use it as a custom function in the math parser. Here is an example that shows our GetSlope function as a delegate function:

static void Main()
    MathParserNet.Parser parser = new MathParserNet.Parser();
    int myDouble;
    double area;
    double slope;

    try {
        parser.RegisterCustomFunction("GetSlope", GetSlope);
        parser.RegisterCustomFunction("Doubler", Doubler);
        parser.RegisterCustomFunction("AreaCircle", AreaCircle);

        area = parser.SimplifyInt("AreaCircle(3.7)");
        myDouble = parser.SimplifyDouble("Doubler(7)");
        slope = parser.SimplifyDouble("GetSlope(-3.2, 12, 8, 13)");
    } catch (Exception ex) {
        throw ex;

static int Doubler(int num)
    return num * 2;

static double AreaCircle(double radius)
    return Math.PI * (radius * radius);

static double GetSlope(double x1,double x2,double y1, double y2)
    return (y1-y2)/(x1-x2);

Delegate functions can have up to 4 parameters. The return type must also be the same as the parameters and the parameters must all be of the same type. The parameters can be int, double, or object. Integer and double types are self-explanatory. If you declare object type parameters, then the objects will be of type MathParserNet.SimplificationReturnValue. This way your function can take both integer and double parameters. In addition, your return type must be object, but that object can be either integer or double. The math parser will take care of everything else!

As with variables and functions, delegate functions can be removed by using the UnregisterCustomFunction() method. You simply pass the function name as a parameter. In addition, you can remove all delegate functions defined by calling the UnregisterAllCustomFunctions() method.

Miscellaneous Methods

There is also a Reset() method. By calling this method, the parser will remove all variables and all functions and all delegate functions created. It is like starting with a brand new, freshly instantiated Parser class.

One last minor feature to talk about is the ToFraction() function. Whenever a function returns a SimplificationReturnValue, that object has a method called ToFraction() which will convert the returned value into a fraction. For example, if your SimplificationReturnValue object had a DoubleValue of 0.25, then calling ToFraction() would return "1/4". I will leave it up to you to play around with that.


I have included a unit test project for testing out the math parsing library. Also, there is a demo Windows Forms project that showcases a lot of the features (if not all) of MathParserNET. If anyone has any questions or feedback, I would always love to hear!


  • 10/30/2011 -- Version 1.1 released. This version now throws exceptions instead of returning values, in the case of an error. In addition, delegate methods have been introduced into this version. Also, the SimplifyInt and SimplifyDouble methods have been created. In addition, I have created a true unit testing project for the Math library and a demo application. Thanks for all the feedback and keep it coming guys!
  • 10/26/2011 -- Initial version released.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Web Developer
United States United States
No Biography provided

You may also be interested in...

Comments and Discussions

SuggestionThanks and a tiny modification Pin
TetheredSun21-Nov-15 3:06
memberTetheredSun21-Nov-15 3:06 
QuestionSAVED MY LIFE! Pin
Member 116755812-Aug-15 2:55
memberMember 116755812-Aug-15 2:55 
QuestionSeparate parse and evaluate Pin
Member 112767231-Dec-14 1:47
memberMember 112767231-Dec-14 1:47 
GeneralMy vote of 5 Pin
Keex0r29-Nov-14 2:34
memberKeex0r29-Nov-14 2:34 
QuestionCompile error Pin
starlily84062918-Sep-14 23:44
memberstarlily84062918-Sep-14 23:44 
QuestionThis rocks Pin
Member 105588534-Apr-14 6:19
memberMember 105588534-Apr-14 6:19 
SuggestionEvent extension Pin
Mike Warden16-May-13 1:20
memberMike Warden16-May-13 1:20 
GeneralParser.Simplify does not work as it should Pin
Salem Hammami16-Apr-13 6:53
groupSalem Hammami16-Apr-13 6:53 
GeneralRe: Parser.Simplify does not work as it should Pin
icemanind22-Apr-13 16:39
membericemanind22-Apr-13 16:39 
GeneralMy vote of 4 Pin
tumbledDown2earth15-Apr-13 22:48
membertumbledDown2earth15-Apr-13 22:48 
Questionimplement integratet function Pin
filmee2419-Dec-12 5:37
memberfilmee2419-Dec-12 5:37 
AnswerRe: implement integratet function Pin
Georg Scholz18-Jan-13 2:00
memberGeorg Scholz18-Jan-13 2:00 
QuestionProblem Pin
alterjo15-Nov-12 2:11
memberalterjo15-Nov-12 2:11 
AnswerRe: Problem Pin
Andres Raieste3-Dec-12 22:48
memberAndres Raieste3-Dec-12 22:48 
It doesn't support globalization. See a thread below for possible solution.
AnswerRe: Problem Pin
icemanind5-Dec-12 5:16
membericemanind5-Dec-12 5:16 
QuestionProblem Pin
alterjo15-Nov-12 1:55
memberalterjo15-Nov-12 1:55 
BugVorzeichenbehandlung / dealing with plus/minus signs Pin
herpo15-Oct-12 9:05
memberherpo15-Oct-12 9:05 
GeneralRe: Vorzeichenbehandlung / dealing with plus/minus signs Pin
icemanind17-Oct-12 9:02
membericemanind17-Oct-12 9:02 
QuestionProblem with double Pin
slawoonet10-Oct-12 0:07
memberslawoonet10-Oct-12 0:07 
AnswerRe: Problem with double Pin
icemanind10-Oct-12 12:14
membericemanind10-Oct-12 12:14 
GeneralAn excellent library Pin
Graham Wilson5-Sep-12 15:40
memberGraham Wilson5-Sep-12 15:40 
GeneralRe: An excellent library Pin
icemanind26-Sep-12 6:52
membericemanind26-Sep-12 6:52 
GeneralMy vote of 5 Pin
Hurty10-Jul-12 0:31
memberHurty10-Jul-12 0:31 
QuestionNew version ? Pin
Andres Raieste9-Jul-12 2:55
memberAndres Raieste9-Jul-12 2:55 
AnswerRe: New version ? Pin
icemanind26-Sep-12 6:54
membericemanind26-Sep-12 6:54 
GeneralRe: New version ? Pin
Andres Raieste26-Sep-12 22:00
memberAndres Raieste26-Sep-12 22:00 
QuestionRegisterCustomFunction in c++/cli? Pin
Member 868581414-Mar-12 8:59
memberMember 868581414-Mar-12 8:59 
AnswerRe: RegisterCustomFunction in c++/cli? Pin
Member 868581414-Mar-12 15:51
memberMember 868581414-Mar-12 15:51 
GeneralRe: RegisterCustomFunction in c++/cli? Pin
Member 868581415-Mar-12 9:18
memberMember 868581415-Mar-12 9:18 
GeneralRe: RegisterCustomFunction in c++/cli? Pin
icemanind19-Mar-12 15:07
membericemanind19-Mar-12 15:07 
QuestionCould you add exponential function? Pin
Member 86841125-Mar-12 3:27
memberMember 86841125-Mar-12 3:27 
AnswerRe: Could you add exponential function? Pin
icemanind9-Mar-12 12:23
membericemanind9-Mar-12 12:23 
QuestionSuggestion to use compiled regex (30% performance gain) Pin
Andres Raieste16-Dec-11 4:23
memberAndres Raieste16-Dec-11 4:23 
GeneralMy vote of 5 Pin
Wes Grant16-Nov-11 5:34
memberWes Grant16-Nov-11 5:34 
QuestionGlobalization issues (ie doesn't work with "3,14" instead of "3.14" number style) Pin
Andres Raieste15-Nov-11 11:34
memberAndres Raieste15-Nov-11 11:34 
AnswerRe: Globalization issues (ie doesn't work with "3,14" instead of "3.14" number style) Pin
icemanind15-Nov-11 19:58
membericemanind15-Nov-11 19:58 
QuestionSome optimizations suggestions... Pin
pavfrang13-Nov-11 2:09
memberpavfrang13-Nov-11 2:09 
GeneralMy vote of 5 Pin
Mihai MOGA12-Nov-11 22:03
memberMihai MOGA12-Nov-11 22:03 
SuggestionUsing variables Pin
derek999910-Nov-11 0:16
memberderek999910-Nov-11 0:16 
GeneralRe: Using variables Pin
icemanind10-Nov-11 18:21
membericemanind10-Nov-11 18:21 
GeneralRe: Using variables Pin
derek999910-Nov-11 23:38
memberderek999910-Nov-11 23:38 
GeneralRe: Using variables Pin
icemanind13-Nov-11 4:24
membericemanind13-Nov-11 4:24 
GeneralMy vote of 5 Pin
cooniur6-Nov-11 23:15
membercooniur6-Nov-11 23:15 
GeneralMy vote of 5 Pin
sebfia3-Nov-11 23:38
membersebfia3-Nov-11 23:38 
SuggestionSuggestions Pin
thatraja2-Nov-11 0:05
mvpthatraja2-Nov-11 0:05 
GeneralRe: Suggestions Pin
icemanind2-Nov-11 12:42
membericemanind2-Nov-11 12:42 
GeneralRe: Suggestions Pin
thatraja3-Nov-11 2:13
mvpthatraja3-Nov-11 2:13 
GeneralMy vote of 5 Pin
aeastham1-Nov-11 0:07
memberaeastham1-Nov-11 0:07 
Suggestionnice Pin
dan o31-Oct-11 23:22
memberdan o31-Oct-11 23:22 
GeneralMy vote of 5 Pin
FlorianRappl27-Oct-11 6:28
memberFlorianRappl27-Oct-11 6:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    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.160212.1 | Last Updated 30 Oct 2011
Article Copyright 2011 by icemanind
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid