Coder Social home page Coder Social logo

exp4j's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

exp4j's Issues

Possible Improper Boolean operators

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?

Numberparsing doesn't honor locale

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.

Validation does not check parentheses

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)

Expression duplication

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

Validation failed when function has 2 parameters

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);

exp4j considers the following expression valid "[A+B)"

How to reproduce

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())

Actual Result

Test code fails

Expected Result

Test code pass

Additional Notes

I believe having a mathematical expression in such form would be incorrect, but maybe there's something I'm unaware of.

Android doesn't support Character.isAlphabetic(ch)

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?

Replaceable and more flexible Tokenizer

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:

  • the set of legal characters of operators is hard-coded in the Operator class
  • the method that creates the Tokenizer, ShuntingYard.convertToRPN is static and thus cannot be replaced
    I suggest the following changes:
  • move the logic for allowed operator chars to the Tokenizer, to make it easier to customise
  • add the Tokenizer as argument to ShuntingYard.convertToRPN and use a factory method in ExpressionBuilder to create ut, so you can replace it in a subclass
    There may be other changes necessary, and I will explore them in a branch. But it may be best to discuss it in this issue first?

Implement constant operation simplification

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?

using angle function and pi

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.

Calculation bug

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!

Validation fails if function has no parameters

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.

Inconsistency in Function.isValidFunctionName()

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
  • etc...

The same goes for the use of Character.isDigit().

is variables() call on builder really necessary?

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:

  • once to call variables
  • then i build the Expression
  • a second to set the variables values.

Seems a little overkill :s
Is there's a way around this?

Thanks

Trigonometric functions in degrees.

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.

Implicit multiplication error

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.

Feature request to take in a number format

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.

"1 1" is evaluated to 11

Since spaces are stripped from the expression before evaluation "1 1" evaluates to 11 which is clearly a bug.

Possibility to modify order of operations.

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

Space before unary minus inside parenthesis throws exception.

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);
    }

Perfomance penalty of ```java.util.Stack```

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.

Add support for validation of absent variables

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.

Errors with validation

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

Function return generic type

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.

Calculation problem

Multiply two integer, then divide by either one of the integer, result is a 15 decimal places number

Version 0.4.6

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. ;)

Support for variable assignment

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

Variable names and multiplication

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?

Allow not predefining (all) variables and lazy-computing variable values

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.

sin90-sin90 doesnt give an output of 0

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

Problem with simple sum accounts

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?

doesn't throw exception for unmatched parenthesis in build

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

Wrong result if variable and function have the same name

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.

Bug when tokenizing a negative sign

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

Get a list of variables to be set

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.

Cannot be serialized

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

Possible factorial error.

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?

Suggestion on Simplification

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?

Is it possible to build the expression without specifying the variables first?

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?

Ability to solve for a varaible

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);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.