fasseg / exp4j Goto Github PK
View Code? Open in Web Editor NEWA tiny math expression evaluator for the Java programming language
Home Page: http://www.objecthunter.net/exp4j/
License: Apache License 2.0
A tiny math expression evaluator for the Java programming language
Home Page: http://www.objecthunter.net/exp4j/
License: Apache License 2.0
Not sure if we have this but can we please add the ability to perform trigonometric calculations such as sin,cos, tan etc in degrees too? Right now it is only radians I believe.
Maybe I missed this, but I don't see a way to solve for a variable. Is there a way to do that? I'd like to be able to do something like this:
double x = new ExpressionBuilder("(4*x)+2=2*(x+6)").build().solveFor("x");
Assert.assertEquals(5, x, 0.0);
Not sure if this is actually supported, but I want to validate a expression formula ensuring that it has all the variables I set on the withVariableNames()
method.
e.g:
public static boolean isValid(final String expr) {
try {
ExpressionBuilder exprBuilder = new ExpressionBuilder(expr)
.withVariableNames("a", "b", "c", "d", "e", "f");
exprBuilder.build();
} catch (UnknownFunctionException | UnparsableExpressionException e) {
Logger.getGlobal().log(Level.SEVERE, null, e);
return false;
}
return true;
}
So if I call that method from above such as:
isValid("a + f");
and it returns me false, as expected to be.
Function with same calls like ("percentage") and with different `number of operands
arguments, the last of functions override themselves.
("percentage", 2)
("percentage", 1)
The following expression gets evaluated although the factorial is in a nonsensical position:
new ExpressionBuilder("3-!2")
.operator(factorial)
.build()
.evaluate()
This should throw an exception
e -> Math.E
π or "pi" (or \u03C0 ) -> Math.PI
φ -> 1.61803398874
This can be done by the person using the library by setting variables but it should be a default, these arent variable.
Could you add support for expressions where the variable names have special characters?
For example "[Salary.BASIC] * 0.40" with the variable as [Salary.BASIC]
If the value of [Salary.BASIC] is $1000.0, the expression result should be $400.0
I've been profiling exp4j
in particular Expression.evaluate()
, from the profiling I gathered the following data (using Netbeans profiler):
Using Stack 100.00%
evaluate() 19633 100.00%
Total Stack 10900 55.52%
Stack.pop() 5219 26.58%
Stack.push() 3361 17.12%
Double.valueOf() 2320 11.82%
HashMap.get() 1479 7.53%
-----------------------------------
Using LinkedList 85.48%
evaluate() 16782 100.00%
Total LinkedList 8938 53.26%
LinkedList.push() 3670 21.87%
LinkedList.pop() 2705 16.12%
Double.valueOf() 2563 15.27%
HashMap.get() 1493 8.90%
-----------------------------------
Using ArrayStack 46.45%
evaluate() 9120 100.00%
Total ArrayStack 971 10.65%
ArrayStack.push() 590 6.47%
ArrayStack.pop() 381 4.18%
HashMap.get() 1452 15.92%
The results show that most of the time used by Expression.evaluate()
is wasted on the use of java.util.Stack
which is backed by java.util.Vector
.
I tested again using java.util.LinkedList
which can be used as a drop in replacement for java.util.stack
, it shows some improvements (~15%) but the boxing/unboxing process still takes up a lot of time.
Finally I've created a simple ArrayStack
class that works with an array of doubles directly and doesn't need to box/unbox nor to adapt the methods from java.util.Vector
to push()
and pop()
. The final result is that the Expression.evaluate()
uses less than 50% of the time.
About the table:
The second column of the table is the total time in ms used by the method in 1M excecutions.
The profiled code was:
public class Test {
static final String EXPRESSION = "log(x) - y * sqrt(x^cos(y)) "
+ "+ 43 / 9 * sin(x) - 3 ^ (-3)";
public static void main(String[] args) {
final Expression expression = new ExpressionBuilder(EXPRESSION)
.variables("x", "y")
.build();
Random rnd = new Random();
double val = 0;
int count = 0;
while (count < 1000000) {
expression.setVariable("x", rnd.nextDouble());
expression.setVariable("y", rnd.nextDouble());
val += expression.evaluate();
count++;
}
System.out.println(val);
}
}
Looking forward now most of the time seems to be used retrieving the variable values.
Hi,
Without wanting to ask for statements to be introduced into the language, I was wanting to be able to chain a number of assignment expressions together, simulating separate assignment statements, and both store and later reference intermediate assigned results within the expression evaluation. For example, assume the variable map is set up with:
a = 2
b = 3
Then:
"(c = a + 2) +
(d = c_3 + b) +
(b = d + 2_b)"
and assuming the exp4j expression evaluation rules, would yield a map with:
a = 2
b = 21
c = 4
d = 15
b has been updated. c and d have been added/set.
If the total addition expression were likely to result in a double overflow, the intermediate expressions could be multiplied by zero, thus avoiding that possibility - this would be ok for me because the overall expression value is unimportant for my purposes.
This would be good enough for what I wanted to do. The assignment operations would update the variable map. Is there any plan to do something like this, or if not, could anyone provide some pointers on how best to modify the code to support this ?
Thanks
Andrew
Howdy.
I noticed by mistake that sometimes I have a blank space before a unary minus within parenthesis, and this breaks exp4j as of version 0.3.5 and up. This is consistent with how it works outside of parenthesis, so maybe it's an intentional thing to do. Just FYI.
/* Works in 0.3.4. */
@Test
public void testUnaryMinusInParenthesisSpace() throws Exception {
ExpressionBuilder b = new ExpressionBuilder("( -1)^2");
double calculated = b.build().calculate();
assertTrue(calculated == 1d);
}
/* Always fails. */
@Test
public void testUnaryMinusSpace() throws Exception {
ExpressionBuilder b = new ExpressionBuilder(" -1 + 2");
double calculated = b.build().calculate();
assertTrue(calculated == 1d);
}
Hi.
I am not sure about this being a bug or not but I will put forward some of my findings.
So I defined the factorial method as given on [(http://www.objecthunter.net/exp4j/)].
I get an exception for 3!-2! but not for 3-2!(I get 1, as expected). But rightfully, (3!)-(2!) gives me the correct answer(i.e, 4).
What can be done in order for 3!-2! to work without having to enter brackets?
I'm working on a charting application which should allow the user to add new time series by entering an expression that refers to existing ones, e.g. make an average of two other series. Each series have a name, so you could e.g. write (s1+s2)/2 to define the average of series s1 and s2. However, the series are grouped and only unique within a group, so it's natural to have a hierarchical naming scheme. The groups aren't named, but can be given a name based on the order. Hence, I end up with names like a_amount and b_amount. What I would like is to allow using $n.name for referring to series name within group n. To do this I need to make a custom Tokenizer that allows $ as the first char of a variable. This is currently not easy or possible, for several reasons:
Hi,
I'm trying to integrate exp4j in my Android app but it's throwing an error:
10-09 19:19:50.135: E/AndroidRuntime(26200): java.lang.NoSuchMethodError: java.lang.Character.isAlphabetic(ch) (Tokenizer.java: 88)
I guess it is because Android is running on java 1.6 but this method was added only on java 1.7.
Is there a workaround for this? can it be fixed?
When I do a sin90-sin90 I get 0.909220...
When I do a sin90 then press equal to and then do -sin90 I get a 0 (which is correct)
Same for (sin90/sin90). Doesn't give 1.
UPDATE : Placing brackets around them solves the issue like (sin90)-(sin90) is 0. But can we also have sin90-sin90 display 0?
Am I missing something here?
Thank You!
Anurag
Perform the following code in java:
Expression e = new ExpressionBuilder("[A+B)").variable("A").variable("B").build();
ValidationResult res = e.validate(false);
assertFalse(res.isValid())
Test code fails
Test code pass
I believe having a mathematical expression in such form would be incorrect, but maybe there's something I'm unaware of.
Hello,
I am noticing some odd behavior when running the validation method. When I have an equation such as "x ++++ 6" it resolves it as being a valid expression. Additionally, I have seen it resolve "x 100" as being true. It seems as though these shouldn't be valid expressions.
Thanks,
Kian
Since spaces are stripped from the expression before evaluation "1 1" evaluates to 11 which is clearly a bug.
https://www.objecthunter.net/jira/browse/EXP-23 introduce this issue.
java.lang.String.isEmpty() was added in Gingerbread (2.3).
android.text.TextUtils has custom isEmpty() method:
public static boolean isEmpty(CharSequence str) {
if (str == null || str.length() == 0)
return true;
else
return false;
}
Hello,
The current of exp4j breaks the serialization mechanism of the DMelt project (http:/jwork.org/dmelt/).
For example, the objects created by the class Expression and ExpressionBuilder cannot be serialized
(java.io.NotSerializableException) due to the keys used to create maps inside exp4j. This problem exists after adding " implements java.io.Serializable" statements for Expression and ExpressionBuilder classes.
best, Sergei
Problem
You all know
sin(pi) = 0
cos(pi/2) = 0
tan(pi/4) = 1
I know it is a rounding problem but the result will be only close to the values above. That could lead to problems in calculations.
Real output right now:
sin(pi) = 122..E-16
cos(pi/2) = 6.12...E-17
tan(pi/4) = 0.999999
Possible solution:
Add a rounding option to the build ExpressionBuilder for angle functions. So i can say round the result of sin/cos/tan to a given numbers after the comma.
I have a function without any parameter ("now()"). Expression evaluation is working perfectly, but the validation fails with the error "Too many operators". If I add a parameter to the function call in the expression ("now(0)"), the validation succeeds. I am using version 0.4.5.
Multiply two integer, then divide by either one of the integer, result is a 15 decimal places number
I am wondering if the call to variables() for variables is really necessary.
My problem is that my variables are stored in a HashMap.
So if i want to respect the current way defining and setting variables then i need to go through my hashmap twice:
Seems a little overkill :s
Is there's a way around this?
Thanks
Personally I have tried wrapping your Expression
class into an EasyExpression
class, so that creating and evaluating a simple expression can be a lot easier. For example,
EasyExpression exp = EasyExpression.of("3x^2 + 2*asin(y) + ln(z)", "x", "y", "z" );
double result = exp.evaluate(3.4, 5, 7);
In the example above, there's no need to use the builder, or to call a lot different methods like setVariable()
, or setVariables()
. The values in the parameters of the evaluate()
method must follow the same order as they were specified upon creation using of()
. But this is usually not a problem because common variables in an expression are just like "a,b,c" or "x,y,z", sometimes "u,v,w". Even though they might not be neighboring letters in the alphabet, it's still easy to sort them up alphabetically when creating an expression.
One more thing about the EasyExpression
- more functions, including all in the java.lang.Math
class, are built-in for every object created by default.
Also for the Function
class, I've wrapped it up into a SafeFunction
, with enforced parameter checking. For example, the sin()
function is supposed to have only one parameter. If a user passes in 2 parameters by accident, an IllegalArgumentException
will be thrown.
Anyway, I'm not saying that I wanna overthrow whatever is already in this library, like the ExpressionBuilder
. But, there should be some extension to this library so that the users who only wish to create some simple expressions won't have to go through such a long & complicated procedure.
Again, keep the powerful features for the users with complex tasks, but do provide an express way for the users who don't need that much.
BTW, how often do you think users would really define their own operators and functions?
There is a critical bug when you use exp4j with custom functions:
My code is
Function ROUND = new Function("ROUND", 2) {
@OverRide
public double apply(double... args) {
return Math.round(args[0]);
}
};
String expression = "ROUND(3,-2)";
Expression e = new ExpressionBuilder(expression)
.function(ROUND) .build();
double result = e.evaluate();
This however throws an "Invalid number of operands available error". The reason is that it wrongly performs the operation 3-2 instead of ROUND(3,-2). I debugged your code and found that in the Tokenizer.java in the function getOperator the final int argc does not check for the TOKEN_SEPARATOR , this causes the "-" to be treated as a subtraction instead of unary minus.
I would very much appreciate it if you could fix this bug.
Thanks,
Vandana
I came about this question on stackoverflow and can reproduce the issue.
http://stackoverflow.com/questions/35632717/exp4j-cant-get-a-good-factorial-operator-working
When parsing an expression with two adjacent operators like "2!+2" an exception is thrown
Hi,
Validation will failed when the function has 2 parameters, the following code will return "Too many operands" error
Expression e = new ExpressionBuilder("pow(A,B)")
.variables("A")
.variables("B")
.build();
ValidationResult res = e.validate(false);
I'm working on an application where the number of allowed variables is potentially very large, so to add them all with their values is costly. Instead, it would be better to 1) collect the used variable names in ExpressionBuilder and 2) be able to iterate through them and set the values of those actually used.
I propose a flag in ExpressionBuilder that controls how tokens that look like variables are handled. If the mode is "allow undefined variables", variable-like tokens that are unknown as either defined variables or functions, are automatically added as variables. Before the evaluate method needs the values, they should of course be set or an exception should be thrown.
I'd like for the ability to get a list of variables as parsed from exp4j to do pre-validation of the variable names. This looks like it would be as simple as exposing a read only set or list of the Expression's variable list.
I've been investigating how to improve the performance of variable value retrieval, and came across something odd, the variable names are checked in Expression#setVariable()
, but they are not checked before building the expression, that is, ExpressionBuilder
passes the variable names to ShuntingYard
and then they are passed to Tokenizer
without any kind of check. Since Tokenizer
checks if a token is a variable before it checks the function names the process seems to work, Expression.evaluate()
even yields a result... BUT the value is wrong.
As an example, the following code should throw a IllegalArgumentException
but it fails silently.
public void test() {
Expression e = new ExpressionBuilder("log10(log10)")
.variables("log10")
.build();
e.setVariable("log10", 1);
System.out.println(e.evaluate()); //The output should be 0 but it's 1
}
I'll send a patch, but the only way I see to fix this issue involves moving around too much code... Basically, moving the validation of variables to ExpressionBuilder#build()
, and changing the way that variables are validated and set in Expression#setVariable()
and Expression#validate()
, plus moving the values to VariableToken
instead of using a different data structure.
Hi i discovered the exp4j and i'm really interested but i´m facing a problem with simple accounts.
like this one 1.2+2.2 the result is always 3.4000000000000004 could it be a bug or there is a way to solve this?
When using exp4j
to paralellize calculations, a several calls to ExpressionBuilder#build()
are needed (one per thread), but in the current implementation of ExpressionBuilder
the process is repeated over and over again.
It seems pretty easy to save the parsed tokens internally until the next call to ExpressionBuilder#build()
that way we won't need to go through the whole ShuntingYard#convertToRPN()
again (this shouldn't break anything, at least in the current codebase, if 9a845e1 is merged then we'll need to clone variable instances).
This issue was raised in https://groups.google.com/forum/#!topic/exp4j/keeZRiMhFaI
There's an inconsistency between Function.getAllowedFunctionCharacters()
and Function.isValidFunctionName()
, the first returns only english ASCII letters, but the later uses Character.isLetter()
which accepts symbols that represent letters in every other language, so for instance (assuming that the accepted characters should be the ones expressed in Function.getAllowedFunctionCharacters()
):
Function.isValidFunctionName("logñ")
should return false
but it returns true
Function.isValidFunctionName("üla")
should return false
but it returns true
The same goes for the use of Character.isDigit()
.
I used the latest exp4j-0.3.11.jar.
When I try to test below expression, I got the incorrect result.
0.1 * 0.1 = 0.010000000000000002
0.2 * 0.2 = 0.04000000000000001
0.4 * 0.4 = 0.16000000000000003
Following is my code sample:
public static void main(String[] args) throws UnknownFunctionException, UnparsableExpressionException {
Calculable calc = new ExpressionBuilder("0.4 * 0.4").build();
System.out.println(calc.calculate());
}
Could you please check and fix? Thanks!
Is it possible to make the class Function generic, so the apply method can do more than arithmetic operations and be able to perform other operations.
There's a small optimization that can be easily implemented, which is to simplify operations that don't contain variables.
For instance: when this expression is parsed 2 + sin(x) + 12 / 4 ^ 2
exp4j generates 2.0 x sin + 12.0 4.0 2.0 ^ / +
when it could generate 2.0 x sin + 0.75 +
or even better 2.75 x sin +
.
I currently have a small working (it passes all of the tests) implementation that is able do the first simplification assuming that all the functions are deterministic (BTW adding a non-deterministic
flag is trivial), the second optimization will be pretty hard without using trees.
I believe that is a good starting point for other types of simplifications like * 1
, / 1
, f(x) + f(x) -> 2 * f(x)
, etc.
Is anyone interested?
Hi!
Can you please add cot
to existing functions?
In Expression.java in the main src package https://github.com/fasseg/exp4j/blob/master/src/main/java/net/objecthunter/exp4j/Expression.java , there is a function called "checkVariableName(String name)" In here, it checks if the instance's custom functions contains the given name OR if the builtin functions contains the given name, then throws an error if the result evaluates to true saying that the variable cannot be a built in variable.
Shouldn't rather be the && operator as it must not be in both user functions AND the builtin functions?
Hi!
As exp4j's builtin operations has a predefined precedence with unary operators higher than exponents, the expression "-3^2" is considered to be "(-3)^2". Most of the time this is ok, but in a special case, I have a need for handling it as "-(3^2)".
To achieve this, I don't see any easy ways in 0.2.9. In 0.3.0 I can add my own CustomOperator but I'm not allowed to use the character ' unless I modify ExpressionBuilder.java to allow it.
I'm requesting a way to modify the precedence, or to simply override any operatior without having to modify the source of your jar package (as I prefer to use it from maven).
Br,
Jan Nylund
Validation does not check if parentheses closes or is open and return true, tho evaluate throws emptystack or mismatched parenthesis error.
Function used : (0.14_1.5)/(((I/600)^0.02)-1)
Incorrect use: (0.14_1.5)/((I/600)^0.02)-1) ; 0.14*1.5)/(((I/600)^0.02)-1)
Hi,
Would it be possible to add support for variable length argument custom Functions ?
I would like to be able to do things like:
x = sum(a, b, c, d, e, f);
y = sum(a, b, c);
Thanks
Andrew
In our application we evaluate lots of equations every second. It seems quite costly to have to create a new instance of ExpressionBuilder, set all the variables and functions for every equation.
It would be great if there could be a setter on ExpressionBuilder using which I could set the equation string on an existing instance of ExpressionBuilder.
Last year I suggested to add signum function and it was added. In changes it is stated as in version 0.4.6, but I am not able to find this version. Has it ever been published? Would be great if this update will find its way to maven repository. ;)
when I plot "x*x-4x" using demo applet on the site it draws a straight line instead of quadratic. It should either show error/exception or should plot quadratic.
I have a situation where users can create arbitrary expressions could include a fraction of the total number of variables available. For example ( "Debt / Equity < 2" ).
I want to be able to build the expression without knowing the variables in advance, allowing the exp4j tokenizer to parse the expression. Then I want to query the expressionbuilder to get the list of variables, set the values, and then evaluate the expression.
The current implementation requires me to know, in advance, which variables are used. How would you suggest I approach this?
On building expression "(x_x+1( " or "x_x*" the expression builder doesn't throw any exception,
although calculable.calculate does so. But I think the unparsable exception should be thrown by builder itself.
e.g
Calculable calc = new ExpressionBuilder("(x*x+y").withVariableNames("x", "y")
.build();
builds succesfully, but on calculating this exception is thrown.
java.lang.ClassCastException: mathparser.ParenthesisToken cannot be cast to mathparser.CalculationToken
In our application we have a requirement that any double value in an equation is converted using a number format.
Example:
format = NumberFormat.getInstance()
Number number = numberFormat.parse(value);
retVal = number.doubleValue();
Using exp4j, it would be nice if the evaluate function accepted a NumberFormat which it would use to convert every double value during the calculation process.
Hi,
I'm using exp4j in TradeTrax (https://github.com/onyxbits/TradeTrax) and would like to integrate it deeper (allowing for calculations to be done wherever numbers can be entered). The thing that keeps me from this is that TradeTrax automatically adapts to the user's locale for formating numbers, but exp4j doesn't, it always uses the "." character for fractions (in germany, we use "," for that purpose). The culprit seems to be Tokenizer.java, line 60, where the dot is hardcoded. Would it be possible to make this a variable which is passed in through the constructor and can be set from the ExpressionBuilder?
The locale specific decimalseperator can be found via java.text.DecimalFormatSymbols.getDecimalSeperator.
Hi!
I have some trouble with variable name ending with number.
Suppose I have variable name 'var1' and expression with this variable like 'var123 + 100'.
In my opinion, ExpressionBuilder should return exception with error 'No variable name var123'.
But this is not happening. ExpressionBuilder evaluate this expression like 'var1 * 23 + 100'.
This incident may cause a lot of mistakes, especially when we have a lot of variables ending with number.
Is there any chance to disable multiplication with no sign '*'? Do you have any other ideas?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.