How to evaluate a math expression given in string form?
With JDK1.6, you can use the built-in Javascript engine.
import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
public class Test {
public static void main(String[] args) throws ScriptException {
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
String foo = "40+2";
System.out.println(engine.eval(foo));
}
}
evaluating expressions containing functions in java
May be use JavaScript interpreter?
First create engine instance and init:
// Manager creates engines by mime/language names.
// It has own global scope for engiges created by it.
ScriptEngineManager manager = new ScriptEngineManager();
// Create JavaScript interpreter instance.
// (Nashorn is bundled JavaScript interpreter)
ScriptEngine scope = manager.getEngineByName("JavaScript");
// Define functions you need
String initialScript = "cos = Math.cos;" // ; or \n
+ "sin = Math.sin;"
+ "tg = Math.tan;"
+ "PI = Math.PI;"
// Any other function
+ "ctg = function (x) { return cos(x)/sin(x); };";
// ...
try {
// Add these functions to scope
scope.eval(initialScript);
} catch(ScriptException ex) {
// Evaluating exceptions, syntax errors are thrown here
}
And then you can evaluate expressions in the "scope" many times:
try {
double d = (double)scope.eval("sin(PI/2) + cos(PI/2)");
System.out.println("Calculated: " + d);
} catch(ScriptException e) {
// ...
}
Be warned:
- There is language interpreting - user can pass any script and...
- ... it can reduce perfomance of application.
You can also use, for example, Jython or JRuby as interpreter.
Evaluating a math expression with variables. (java 8)
Sorry for the confusion. The "parse
" function I referred to is simply the existing eval
function, but renamed since it returns an Expression
object.
So you'd have:
public static Expression parse(String str, Map<String,Double> variables) { ... }
And invoke it by:
Map<String,Double> variables = new HashMap<>();
Expression exp = parse("x+(sqrt(x))", variables);
for (double x = 100; x <= +120; x++) {
variables.put("x", x);
System.out.println(x + " => " + exp.eval());
}
One other thing: It's necessary to know at parse time whether a name refers to a variable or a function, in order to know whether or not it takes an argument, but you can't call containsKey
on the variables map during the parse, since the variables might not be present in the map until exp.eval()
is called! One solution is to put functions in a map instead, so you can call containsKey
on that:
} else if (ch >= 'a' && ch <= 'z') { // functions and variables
while (ch >= 'a' && ch <= 'z') nextChar();
String name = str.substring(startPos, this.pos);
if (functions.containsKey(name)) {
DoubleUnaryOperator func = functions.get(name);
Expression arg = parseFactor();
x = () -> func.applyAsDouble(arg.eval());
} else {
x = () -> variables.get(name);
}
} else {
And then somewhere at class level, initialize the functions
map:
private static final Map<String,DoubleUnaryOperator> functions = new HashMap<>();
static {
functions.put("sqrt", x -> Math.sqrt(x));
functions.put("sin", x -> Math.sin(Math.toRadians(x)));
functions.put("cos", x -> Math.cos(Math.toRadians(x)));
functions.put("tan", x -> Math.tan(Math.toRadians(x)));
}
(It would also be okay to define the functions
map as a local variable inside the parser, but that adds a little bit more overhead during each parse.)
Creating a calculator to evaluate arithmetic expressions in Java - code troubles
The main reason you algorithm fails is due to using ==
when trying to check for String
equality.
In Java, ==
is a boolean operator which behaves identically for all operands, and checks the equality of the values of the operands. This means that primitives are checked as one might expect, but Strings, which are objects, will result in comparing the memory references of the two Strings, which will result in true only if the two Strings are actually the same String. This means that String equality checks must be done with the equals
method.
There are more issues with the behavior of the calculator (algorithmic ones), but those will be easier to identify and fix after handling the String equality checks. One example of an issue that must be fixed is:
while(!ops.isEmpty() && nums.size() > 1)
{
String ab = ops.pop();
double bb = nums.pop();
double cb = nums.pop();
double clac = applyOperator(bb,ab,cb);
nums.add(clac);
}
The operands (bb
and cb
) are popped from a Stack, therefore they arrive in a reveresed order (when parsed, cb
was pushed into the stack before bb
). This means that cb
is the leftside operand and bb
is the rightside operand -> double clac = applyOperator(cb,ab,bb);
The same refactoring should be done for all usages of the applyOperand
method.
Another issue is the following:
else if (prec(tokens [i]) < prec(ops.peek()) && !ops.isEmpty() && ops.peek() != "(")
{
String ac1 = ops.pop();
double res1 = nums.pop();
double res2 = nums.pop();
double outcome = applyOperator(res1,ac1,res2);
nums.add(outcome);
}
An internal evaluation was made, but the triggering of the evaluation is the discvery of an operand with a lower presendence. The operand should be pushed into the operations stack after the evaluation:
else if (prec(tokens [i]) < prec(ops.peek()) && !ops.isEmpty() && ops.peek() != "(")
{
...
...
nums.add(outcome); // I highly suggest refactoring this to nums.push due to readability considerations
ops.push(tokens[i]);
}
References:
- The difference between == and equals in Java
- Guide for implementing a scientific calculator (in c++, use as an algorithmic reference)
- The Shunting Yard Algorithm - As suggested by user207421
Expression evaluation in java
From Java 6, you could use the built-in Javascript engine.
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine eng = sem.getEngineByName("JavaScript");
String str = "5*8-9/7+5-8";
System.out.println(eng.eval(str));
Note: The eval()
method throws a ScriptException
and you'll also need the below imports.
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
Related Topics
Problems Converting Byte Array to String and Back to Byte Array
Selenium 2.53 Not Working on Firefox 47
Using Heapdumponoutofmemoryerror Parameter for Heap Dump for Jboss
How to Get Java 11 Run-Time Environment Working Since There Is No More Jre 11 for Download
Can't Read and Write a Tiff Image File Using Java Imageio Standard Library
How to Fix Role in Spring Security
Comparing Java Enum Members: == or Equals()
Converting Between Java.Time.Localdatetime and Java.Util.Date
Url to Load Resources from the Classpath in Java
Java - Convert Integer to String
Convert a JSON String to a Hashmap
Delete Directories Recursively in Java
How Can a String Be Initialized Using " "
Spring 4 Loading Static Resources
Overload with Different Return Type in Java
Java:If a Extends B and B Extends Object, Is That Multiple Inheritance