- JavaDoc

# Jep Java

- Introduction
- Basic Usage
- Variables
- Data types
- Operators
- Functions
- Custom Functions
- BigDecimal
- Modules
- Printing
- FAQ
- Migration
- Version History

# Advanced Features

- Manipulating Expressions
- Components
- Configurable Parser
- Serialization
- Threads
- Localization
- Grammar
- Other advanced features
- Use of Design Patterns in Jep

# Frequently Asked Questions

- Why is Jep giving inaccurate results?
- How should I handle NULL values?
- Why am I getting an EvaluationException?
- How can I allow variable names with a dot in them?
- How can I reduce the size of Jep?

## Why is Jep giving inaccurate results?

You will notice that when you evaluate something as simple as "8 - 7.9" the result will be 0.09999999999999964 rather than 0.1. These inaccuracies are the result of floating point arithmetic. Internally, Jep uses the `double` type to represent numbers by default. Unfortunately, even for trivial calculations such as "8 - 7.9" the calculation can not be performed accurately.

You will notice the same if you run the following code.

    double a=8, b=7.9;
    System.out.println("a-b = " + (a-b));
    //prints a-b = 0.09999999999999964

So this is not a Jep flaw, just a limitation of using floating point numbers. Although floating point numbers are accurate enough for many applications, these types of errors should not be ignored in applications where accuracy is critical.

By using System.out.printf(), results from Jep can be displayed to a given number of decimal places. For example

    jep.parse("8-7.9");
    double res = jep.evaluateD();
    System.out.printf("%.3f",res);

This will print the result to three decimal places: 0.100. See java.util.Formatter for details on formatting output. The java.text.NumberFormat class can also be used to format results.

Jep has a round function, which can round arguments to a given number of decimal places. `round(8-7.9,1)` will round results to one decimal place.

To avoid this problem, you can also use the BigDecimal components as described in the BigDecimal section. They allow you to perform calculations with arbitrary accuracy unlike floating point arithmetic.

## How should I handle NULL values?

If Jep is throwing an exception `"EvaluationException: Could not evaluate XXX : no value set for the variable.`" during evaluation, then you are running into issues with null values.

It is important to note that by default variables whose values have not been set by either

    jep.addVariable(name,value);

or by parsing an expression like

    XXX = 123.456;

will remain initialized to null. So when you attempt to evaluate an expression with a null variable, the evaluator will by default throw an exception when the null value is encountered.

There are a several of ways around this:

1. Depending on the evaluator you are using, you can turn off the check for null values with

       ((StandardEvaluator)jep.getEvaluator()).setTrapNullValues(false);

   or

       ((FastEvaluator)jep.getEvaluator()).setTrapNullValues(false);

   in which case null values will be passed to the individual functions.
2. You can change the default value used for unassigned variables with

       jep.getVariableFactory().setDefaultValue(Double.valueOf(0.0));

3. A more advanced treatment of null values would be to create a type to represent genuine null values, create a constant NULL to recognize NULL in the parser and explicitly set NULL variables.

       Object MyNULL = new Object(); // create a null value
       jep.addConstant("NULL",MyNULL); // define a constant in the parser
       jep.addVariable("x",MyNULL); // add a variable with the NULL value
       jep.parse("y=NULL"); // expression assigning a variable to NULL
       jep.parse("x==NULL"); // Compare a variable to the NULL value

4. Since version 3.4, the com.singularsys.jep.misc.nullwrapper package allows for null values to be treated like NULL in an SQL database. Any function or operator with `null` as an argument will return `null`. For instance `null+5` will be null. The package takes existing operators and functions and adds a wrapper class which will test if a null value is input; if so, null is returned, otherwise the original function is used. The `NullWrappedOperatorTable` and `NullWrappedFunctionTable` wrap all the existing operators and functions. To set this up use

       jep.setComponent(new NullWrappedOperatorTable(
                         (OperatorTable2) jep.getOperatorTable(),true));
       jep.setComponent(new NullWrappedFunctionTable(jep.getFunctionTable()));
       jep.setComponent(new StandardConfigurableParser());
       ((FastEvaluator) jep.getEvaluator()).setTrapNullValues(false);

   The operator table also adds an additional operator, the null safe equals `<=>` which works like equals, but if both arguments are null will return true. This needs the `StandardConfigurableParser` for the operator to be recognized when parsing.

   The logical operators work like those in SQL, so `null || true` is true, `null || false` is null, `null && true` is null and `null && false` is false. See NullWrappedLazyLogical for the complete truth tables.

   The `If` function just tests the first argument for null, returning null if it is. If the first argument is true or false it will return the second or third argument respectively, these arguments can be null.

   The names of classes have been changed in version 3.5 and they generally begin `NullWrapped...`.

## Why am I getting an EvaluationException?

There can be several reasons for EvaluationExceptions to be thrown. Of course, it is best to look at the message in the exception for more details.

If you are seeing

    com.singularsys.jep.EvaluationException: Could not evaluate XXX : no
        value set for the variable.

then refer to "How should I handle NULL values?" in this FAQ.

Other evaluation exceptions are typically due functions or operators not being compatible with the data types passed in. Since Jep only checks data types during evaluation, you will not see these issues while parsing an expression.

## How can I allow variable names with a dot in them?

To do this, you need to use the Configurable Parser which allows great control over the input syntax. The following code sets up the parser with the standard options but using identifiers with a dot in them as well by using the factory method com.singularsys.jep.configurableparser.matchers.IdentifierTokenMatcher.dottedIdentifierMatcher(). The final step in setting up is to remove the dot-product "." operator to prevent any ambiguity.

    ConfigurableParser cp = new ConfigurableParser();
    cp.addHashComments();
    cp.addSlashComments();
    cp.addDoubleQuoteStrings();
    cp.addWhiteSpace();
    cp.addExponentNumbers();
    cp.addOperatorTokenMatcher();
    cp.addSymbols("(",")","[","]",",");
    cp.setImplicitMultiplicationSymbols("(","[");

    // Sets it up for identifiers with dots in them.
    cp.addTokenMatcher(IdentifierTokenMatcher.dottedIdentifierMatcher());

    cp.addSemiColonTerminator();
    cp.addWhiteSpaceCommentFilter();
    cp.addBracketMatcher("(",")");
    cp.addFunctionMatcher("(",")",",");
    cp.addListMatcher("[","]",",");
    cp.addArrayAccessMatcher("[","]");

    // Construct the Jep instance and set the parser
    jep = new Jep(cp);

    // Remove the dot operator
    OperatorTable2 ot = (OperatorTable2)jep.getOperatorTable();
    ot.removeOperator(ot.getDot());
    //notify other components of change in operator table
    jep.reinitializeComponents();

## How can I reduce the size of Jep?

The memory footprint of Jep can be reduced in a number of ways.

- By using the `StandardConfigurableParser` rather than the default parser. This takes considerably less runtime space (4K) compared to 51K.
- If you do not need a parser you can use the `NullParser` which take virtually no space. This can be used with SerializableExpression where a compact representation of an expression can be stored on disk.
- By not loading any functions. This can be achieved by using the `FunctionTable` component rather than the `StandardFunctionTable`. Any functions needed can then be individually loaded using `Jep.addFunction()`.

For example you could create a Jep instance with no loaded functions with:

    Jep jep1 = new Jep(new FunctionTable(), new StandardConfigurableParser());

And you can create a Jep instance without parser, without functions and without the ability to print with:

    Jep jep2 = new Jep(new FunctionTable(),
            NullParser.NULL_PARSER, PrintVisitor.NULL_PRINT_VISITOR);

The com.singularsys.jepexamples.diagnostics.ExamineSizes program gives a detailed breakdown of memory usage.

To reduce the disk space the `com/singularsys/jep/misc`, `com/singularsys/jep/walkers`, `com/singularsys/jep/bigdecimal` packages are all optional. None of the classes in the `com/singularsys/jepexamples` or `com/singularsys/jeptest` directories are needed. If the configurable parser is used then in the `com/singularsys/jep/parser` directory the `JccParser*` classes can all be skipped. Alternatively if the standard parser is used then the `com/singularsys/jep/configurableparser` package can be skipped completely.

The `jep-java-withexamples.jar` jar file is a fairly small example with a full set of functions and a working console application. which is less that 200K in size.

## How to work with very large expressions

The size of expressions which can be worked with is mainly limited by the stack size allocated to java. This can be increased by using the `-Xss512k` argument to the Java VM. The `ConfigurableParser` can generally parse larger expressions than the standard parser. The PostfixEvaluator has been written to not make heavy use of the stack and can evaluate expressions with over a million nodes. The DestructiveTests application tests the size of expressions which can be parsed and evaluated.