Skip to content

Evaluating an expression

amomra edited this page Apr 21, 2015 · 3 revisions

Evaluating an expression

Setting the expression

The Parser class have a property Expr which holds the expression to be evaluated.

parser.Expr = "1 + 1";

Single return expression evaluation

Expression evaluation is done by calling the Eval() member function of a parser object. When evaluating an expression for the first time the parser evaluates the expression string directly and creates a bytecode during this first time evaluation. Every sucessive call to Eval() will evaluate the bytecode directly unless you call a function that will silently reset the parser to string parse mode. Some functions invalidate the bytecode due to possible changes in callback function pointers or variable addresses. By doing so they effectively cause a recreation of the bytecode during the next call to Eval().

Internally there are different evaluation functions. One for parsing from a string, the other for parsing from bytecode (and a third one used only if the expression can be simplified to a constant). Initially, Eval() will call the string parsing function which is slow due to all the necessary syntax checking, variable lookup, and bytecode creation. Once this function succeeds, Eval() will change its internal parse function pointer to either the bytecode parsing function or the const result function which are significantly (approx. 1000 times) faster. You don't have to worry about this, it's done automatically, just keep in mind that the first time evaluation of an expression is significantly slower than any successive call to Eval().

try
{
    double val = parser.Eval();
}
catch (ParserError e)
{
    Console.WriteLine(e.Message);
}

If the expression contains multiple separated subexpressions the return value of Eval() is the result of the last subexpression. If you need all of the results use the functions described in the next sections.

Multiple return expression evaluation

muParser and, consequently, muParserNET accepts expressions that are made up of several subexpressions delimited by the function argument separator. For instance take a look at the following expression:

sin(x),y+x,x*x

It is made up of three expression separated by commas hence it will create three return values. (Assuming the comma is defined as the argument separator). Their value can be queried with the call of the EvalMulti function. This returns an array of double holding the actual values with the first value at the botton of the array and the last at the top.

double[] vals = p.EvalMulti();

for (int i = 0; i < vals.Length; i++)
{
    Console.WriteLine(vals[i]);
}

Bulk mode evaluations

The basic idea behind the bulkmode is to minimize the overhead of function calls and loops when using muParser inside of large loops. Each loop turn requires a distinct set of variables and setting these variables followed by calling the evaluation function can by slow if the loop is implemented in a managed language. This overhead can be minimized by precalculating the variable values and calling just a single evaluation function. In reality the bulkmode doesn't make much of a difference when used in C++ but it brings a significant increase in performance when used in .NET applications. If muParser was compiled with OpenMP support the calculation load will be spread among all available CPU cores. When using the bulk mode variables created with DefineVar function must be initializated with arrays instead of single variables. All variable arrays must have the same size and each array index represents a distinct set of variables to be used in the expression.

try
{
    Parser p = new Parser();
    p.DefineVar("a", new double[]{ 1, 2, 3, 4, 5});
    p.DefineVar("b", new double[]{ 6, 7, 8, 9, 10});

    p.Expr = "a + b";

    double[] results = p.EvalBulk(5);

    for (int i = 0; i < results.Length; i++)
    {
        Console.WriteLine(results[i]);
    }
}
catch (ParserError e)
{
    Console.WriteLine(e.Message);
}
Clone this wiki locally