About

exp4j is capable of evaluating expressions and functions in the real domain. It's a small (40KB) library without any external dependencies, that implements Dijkstra's Shunting Yard Algorithm. It comes with a standard set of built-in functions and operators, in addition users are able to create custom operations and functions for use in their mathematical expressions.

Evaluate a simple expression:

Calculable calc = new ExpressionBuilder("3 * sin(y) - 2 / (x - 2)")
        .withVariable("x", varX)
        .withVariable("y", varY)
        .build()
double result1=calc.calculate();

Variable declaration

Variable names must start with a letter or the underscore (_) and can only include letters, digits or underscores.

the following are valid variable names: * varX * _x1 * _var_X_1 while for e.g. 1_var_x is not as it does not start with a letter or a underscore.

One has to make sure that the variable names are passed into the ExpressionBuilder before calling build(). If variables are used in the expression without setting at least their names, an UnparseableErpessionExcetion will be thrown. The following three examples demonstrate the different possibilities to have exp4j recognize variables:

API changed in 0.3.0: Implicit variable declaration no longer possible!

The feature to use implicit variable declarations as in new ExpressionBuilder("f(x,y)=x*y") has been removed. You will have to use ExpressionBuilder.withVariableNames() or ExpressionBuilder.withVariable() for variable declaration.

Using ExpressionBuilder.withVariableNames():

Calculable calc = new ExpressionBuilder("x * y - 2")
        .withVariableNames("x","y")
        .build();
calc.setVariable("x",1);
calc.setVariable("y",2);
assertTrue(calc.calculate()==0);

Using ExpressionBuilder.withVariable()

Calculable calc = new ExpressionBuilder("x * y - 2")
        .withVariable("x",1);
        .withVariable("y",2);
        .build();
assertTrue(calc.calculate()==0);

Scientific notation

Since version 0.3.5 it is possible to use scientific notation for numbers (see http://en.wikipedia.org/wiki/Scientific_notation). The number is split into a significand/mantissa (y) and exponent (x) of the form 'yEx' which is evaluated as 'y * 10^x'. Be aware that 'e/E' is no operator and therefore an expression like "1.1e-(x*2)" can not be evaluated. An example using the Fine-structure constant 'α=7.2973525698 * 10^−3':

String expr = "7.2973525698e-3";
double expected = 7.2973525698d * Math.pow(10, -3);
Calculable calc = new ExpressionBuilder(expr).build();
assertTrue(expected == calc.calculate());

Custom functions

you can extend the abstract class CustomFunction in order to use custom functions in expressions. you only have to implement the applyFunction(double[] values) method.

CustomFunction fooFunc = new CustomFunction("foo") {
    public double applyFunction(double[] values) {
                return values[0]*Math.E;
        }
};
double varX=12d;
Calculable calc = new ExpressionBuilder("foo(x)")
        .withCustomFunction(fooFunc)
        .withVariable("x",varX)
        .build();
assertTrue(calc.calculate() == Math.E * varX);

you can also define multi argument functions like max(a,b,c) via the constructor CustomFunction(String name,int argc), with argc being the argument count.

CustomFunction custom1 = new CustomFunction("max",3) {
    @Override
    public double applyFunction(double[] values) {
        double max=values[0];
        for (int i=1;i<this.getArgumentCount();i++) {
            if (values[i] > max) {
                max=values[i];
            }
        }
        return max;
    }
};
double varX=Math.E;
Calculable calc = new ExpressionBuilder("max(log(x),sin(x),x)")
        .withVariable("x", varX)
        .withCustomFunction(custom1)
        .build();
assertTrue(varX == calc.calculate());

Custom operators

you can extend the abstract class CustomOperator in order to declare custom operators for use in expressions, with the symbol being one of !,#,§,$,&,;,:,~,<,>,|,=. Be aware that adding a CustomOperator with a used symbol overwrites any existing operators including the builtin ones. So it's possible to overwrite e.g. the '+' operator. The Constructor of a CustomOperator takes up to 4 arguments:

  • the symbol used for this operation (one of !,#,§,$,&,;,:,~,<,>,|,=)
  • if the operation is left associative
  • the precedence of the operation
  • the number of operands the operator has (1 or 2)
    CustomOperator factorial = new CustomOperator('!', true, 6, 1) {
            @Override
        double applyOperation(double[] values) {
            double tmp = 1d;
            int steps = 1;
            while (steps < values[0]) {
                    tmp = tmp * (++steps);
            }
            return tmp;
        }
    };
    Calculable calc = new ExpressionBuilder("11!").withOperation(factorial).build();
    assertTrue(39916800d == calc.calculate());
    

Built-in operators

  • Addition: '2 + 2'
  • Subtraction: '2 - 2'
  • Multiplication: '2 * 2'
  • Division: '2 / 2'
  • Exponentation: '2 ^ 2'
  • Unary Minus,Plus (Sign Operators): '+2 - (-2)'
  • Modulo: '2 % 2'

Precedence of unary minus

In order to accommodate different use cases the precedence for the unary operators in respect to exponentiation can be set via the System property "exp4j.unary.precedence.high". You can set the property via System.getProperty(PROPERTY_UNARY_HIGH_PRECEDENCE,"false") in order to change evaluation from an expression like "-3^2" from "(-3)^2" to "-(3^2)":

String expr = "-3^2";
System.setProperty(ExpressionBuilder.PROPERTY_UNARY_HIGH_PRECEDENCE, "false");
Calculable calc = new ExpressionBuilder(expr).build();
assertTrue(-Math.pow(3, 2) == calc.calculate()); // evaluates to '-9'

System.clearProperty(ExpressionBuilder.PROPERTY_UNARY_HIGH_PRECEDENCE);
calc = new ExpressionBuilder(expr).build();
assertTrue(Math.pow(-3,2) == calc.calculate()); // evaluates to '9'

Division by zero in operations and functions

exp4j throws a ArithmeticException when a division by zero is attempted. When implementing CustomOperator or CustomFunction involving divisions the implementor has to make sure that a corresponding RuntimeException is thrown. The following example from the exp4j sources shows how to check for such a condition.

                CustomOperator mod = new CustomOperator("%", true, 3) {
                        @Override
                        protected double applyOperation(double[] values) {
                                if (values[1] == 0d){
                                        throw new ArithmeticException("Division by zero!");
                                }
                                return values[0] % values[1];
                        }
                };

Built-in functions

  • abs: absolute value
  • acos: arc cosine
  • asin: arc sine
  • atan: arc tangent
  • cbrt: cubic root
  • ceil: nearest upper integer
  • cos: cosine
  • cosh: hyperbolic cosine
  • exp: euler's number raised to the power (e^x)
  • floor: nearest lower integer
  • log: logarithmus naturalis (base e)
  • sin: sine
  • sinh: hyperbolic sine
  • sqrt: square root
  • tan: tangent
  • tanh: hyperbolic tangent

API changes

  • Version 0.3.2: choice for unary minus precedence via System property
  • Version 0.3.0: implicit variable declarations á la "f(x)=2x" have been removed
  • Version 0.3.0: PostfixExpression API has been removed
  • Version 0.3.0: The CustomOperator API has been added
  • Version 0.2.5: the argument type for CustomFunction changed from double to double[] with an array holding the arguments of the function call, in order to allow multi argument functions like max(x,y,z)
  • Version 0.2.2: the PostfixExpression API has been marked deprecated.
  • Version 0.2.1: the CustomFunction API has been added
  • Version 0.2.0: the ExpressionBuilder/Calculable API has been added

Links

References

  • Nilgiri MUD uses exp4j
  • JamWiki a java based wiki uses exp4j
  • Catalin Alexandru blogged about exp4j
  • JComplexity for algortihm comparison uses exp4j
  • free{dom} building automation framework uses exp4j
  • jHepWork a Multiplatform environment for scientific computation and data analysis uses exp4j
  • cacl3d a 3d calculus visualisation engine uses exp4j.

    Please let me know if you're project uses exp4j and you want it listed here