Introduction
This article features a C# wrapper for the muParser DLL. muParser
is a fast mathematical expressions parser which transforms a mathematical expression into bytecode. Since writing it, I have received some queries about using the parser with .NET. So far, no real solution existed since muParser
is native C++ code. This project will close the gap between the unmanaged parser DLL and the managed .NET environment. It is not meant to give you a detailed overview on muParser
itself. Please use the following pages for this:
The functionality and member functions of the C# wrapper are almost identical, with a few exceptions mentioned in this document.
Features
The aim of this code is to provide a complete wrapper of muParser
. Some of the more advanced and rarely used features could not be made accessible due to their intrinsic "unmanaged" nature. The following list shows you what features are available in C#:
- User-defined operators
- binary operators
- postfix operators
- infix operators
- User-defined functions
- with a fixed number of up to five arguments
- with variable number of arguments
- with a single string argument (for database queries)
- User-defined constants
- numeric constants
- string constants
- User-defined variables
- unlimited in number
- assigning variables in terms of other variables is possible
- Custom value recognition callbacks
- support for binary and hex values
- can be used to implement database queries
- Parser functions/operators
The following table gives an overview of the functions supported by the default implementation. It lists the function names, the number of arguments and a brief description.
Name |
Argc. |
Explanation |
sin |
1 |
sine function |
cos |
1 |
cosine function |
tan |
1 |
tangens function |
asin |
1 |
arcus sine function |
acos |
1 |
arcus cosine function |
atan |
1 |
arcus tangens function |
sinh |
1 |
hyperbolic sine function |
cosh |
1 |
hyperbolic cosine |
tanh |
1 |
hyperbolic tangens function |
asinh |
1 |
hyperbolic arcus sine function |
acosh |
1 |
hyperbolic arcus tangens function |
atanh |
1 |
hyperbolic arcus tangens function |
log2 |
1 |
logarithm to the base 2 |
log10 |
1 |
logarithm to the base 10 |
log |
1 |
logarithm to the base 10 |
ln |
1 |
logarithm to base e (2.71828...) |
exp |
1 |
e raised to the power of x |
sqrt |
1 |
square root of a value |
sign |
1 |
sign function, -1 if x<0; 1 if x>0 |
rint |
1 |
round to nearest integer |
abs |
1 |
absolute value |
if |
3 |
if ... then ... else ... |
min |
var. |
min of all arguments |
max |
var. |
max of all arguments |
sum |
var. |
sum of all arguments |
avg |
var. |
mean value of all arguments |
The following table lists the default binary operators supported by the parser:
Operator |
Meaning |
Priority |
= |
assignment* |
-1 |
and |
logical AND |
1 |
or |
logical OR |
1 |
xor |
logical XOR |
1 |
<= |
less or equal |
2 |
>= |
greater or equal |
2 |
!= |
not equal |
2 |
== |
equal |
2 |
> |
greater than |
2 |
< |
less than |
2 |
+ |
addition |
3 |
- |
subtraction |
3 |
* |
multiplication |
4 |
/ |
division |
4 |
^ |
raise x to the power of y |
5 |
*The assignment operator is special since it changes one of its arguments and can only be applied to variables.
How It Works
The wrapper defines three classes:
Parser
and ParserException
are similar to their C++ counterparts and will not be documented here in detail. For details, refer to the C++ documentation and the sample source code.
ParserVariable
is new and encapsulates a double
value used as a variable. This is necessary since for each variable muParser
needs a pointer to double
. Using C#, it is hard to get a pointer that remains fixed during the lifetime of a class. ParserVariable
avoids this trouble by using the DLL itself to create and release a pointer to double
. In short, it hides the variable pointer from the garbage collector.
Using the Code
In order to use the code, you need the muParser.dll which is part of this archive. Make sure to place a copy of the DLL into your application directory or in a directory where the system can find it. Finally, add the file muParser.cs to your project. The following code samples assume you are either in namespace muParser
or have a corresponding using muParser
statement.
Setting Up the Parser
In order to use the parser, create an instance of it.
Collapse | Copy Code Parser parser = new Parser(Parser.EBaseType.tpDOUBLE);
By using
Parser.EBaseType.tpINT
or
Parser.EBaseType.tpDOUBLE
as a parameter to the parser constructor you can either select an instance working with integer values or the standard instance working with double values.
Defining Variables
Create an instance of a ParserVariable
and set up a corresponding parser variable. You can default initialize the variable to a user defined value using the constructor.
Collapse | Copy Code ParserVariable var = new ParserVariable(10);
parser.DefineVar("my_var", var);
Setting Up and Calculating an Expression
Finally, set up the expression and calculate the result.
Collapse | Copy Code parser.SetExpr("10*sin(my_var)");
double val = parser.Eval();
Defining Custom Functions
You can set up your own functions and operators using delegates. The parser defines the following type that must be implemented in your code in case you'd like to use custom functions:
Collapse | Copy Code public delegate double Fun1Delegate(double val1);
public delegate double Fun2Delegate(double val1, double val2);
public delegate double Fun3Delegate(double val1, double val2, double val3);
public delegate double Fun4Delegate(double val1, double val2, double val3,
double val4);
public delegate double Fun5Delegate(double val1, double val2, double val3,
double val4, double val5);
public delegate double StrFun1Delegate(String name);
public delegate double StrFun2Delegate(String name, double val1);
public delegate double StrFun3Delegate(String name, double val1, double val2);
public delegate double MultFunDelegate(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] double[] array,
int size);
Registering callbacks can be done like this:
Collapse | Copy Code parser.DefineFun("fun1", new muParser.Fun1Delegate(fun1) );
parser.DefineFun("fun2", new muParser.Fun2Delegate(fun2) );
parser.DefineFun("fun3", new muParser.Fun3Delegate(fun3) );
parser.DefineFun("fun4", new muParser.Fun4Delegate(fun4) );
parser.DefineFun("fun5", new muParser.Fun5Delegate(fun5) );
parser.DefineFun("prod", new muParser.MultFunDelegate(prod) );
parser.DefineOprt("%", new muParser.Fun2Delegate(fun2), 2 );
parser.DefinePostfixOprt("m", new muParser.Fun1Delegate(fun1));
The first parameter to DefineFun
or DefineOprt
is the identifier, the second parameter is the delegate used as callback.
Dealing with Errors
Errors are reported by throwing an exception of type ParserException
. Use the member functions of this class to get the error details.
Collapse | Copy Code try
{
parser = new muParser();
}
catch (ParserException exc)
{
string sMsg;
sMsg += string.Format(" Expression: \"{0}\"\n", exc.Expression);
sMsg += string.Format(" Message: \"{0}\"\n", exc.Message);
sMsg += string.Format(" Token: \"{0}\"\n", exc.Token);
sMsg += string.Format(" Position: {0}\n", exc.Position);
Console.WriteLine(sMsg);
}
Copyright (c) 2007 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
History
- Rev. 1.00 - 09.04.2007
Initial release of the muParser
C# wrapper