Revert "Add support for implicit multiply in equations"
This reverts commit a218a8276b
.
This commit is contained in:
@@ -6,8 +6,6 @@ import java.util.NoSuchElementException;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Implements evaluation for simple math expressions using the shunting yard
|
||||
* algorithm.
|
||||
@@ -15,62 +13,47 @@ import javax.annotation.Nullable;
|
||||
public class EquationEvaluator {
|
||||
|
||||
public static double evaluate(String input) {
|
||||
final StringTokenizer tokens = new StringTokenizer(input, "+-*/()", true);
|
||||
final Deque<String> operators = new ArrayDeque<>();
|
||||
final Deque<Double> operands = new ArrayDeque<>();
|
||||
StringTokenizer tokens = new StringTokenizer(input, "+-*/()", true);
|
||||
Deque<String> operators = new ArrayDeque<>();
|
||||
Deque<Double> operands = new ArrayDeque<>();
|
||||
String lastToken = null;
|
||||
while (tokens.hasMoreTokens()) {
|
||||
String rawToken = tokens.nextToken().trim();
|
||||
if (rawToken.isEmpty())
|
||||
continue;
|
||||
if (isUnaryMinus(rawToken, lastToken)) {
|
||||
rawToken = "u";
|
||||
} else if (isImplicitMultiply(rawToken, lastToken)) {
|
||||
lastToken = processToken(input, "*", operators, operands);
|
||||
|
||||
boolean isUnaryMinus = rawToken.equals("-") && (lastToken == null
|
||||
|| (!lastToken.equals("u") && isOperator(lastToken)) || lastToken.equals("("));
|
||||
final String token = isUnaryMinus ? "u" : rawToken;
|
||||
if (isOperator(token)) {
|
||||
popOperators(input, operators, operands,
|
||||
top -> (!top.equals("(") && getPrecedence(token) <= getPrecedence(top)));
|
||||
operators.push(token);
|
||||
} else if (token.equals("(")) {
|
||||
operators.push(token);
|
||||
} else if (token.equals(")")) {
|
||||
popOperators(input, operators, operands, top -> !top.equals("("));
|
||||
if (!operators.pop().equals("(")) {
|
||||
throw new IllegalArgumentException("Unbalanced right parentheses in expression: " + input);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
operands.push(Double.parseDouble(token));
|
||||
} catch (NumberFormatException exception) {
|
||||
throw new IllegalArgumentException("Could not evaluate expression: " + input);
|
||||
}
|
||||
}
|
||||
lastToken = processToken(input, rawToken, operators, operands);
|
||||
lastToken = token;
|
||||
}
|
||||
popOperators(input, operators, operands, top -> true);
|
||||
return operands.pop();
|
||||
}
|
||||
|
||||
private static boolean isUnaryMinus(String rawToken, @Nullable String lastToken) {
|
||||
return rawToken.equals("-")
|
||||
&& (lastToken == null || (isOperator(lastToken) && !lastToken.equals("u")) || lastToken.equals("("));
|
||||
}
|
||||
|
||||
private static boolean isImplicitMultiply(String rawToken, @Nullable String lastToken) {
|
||||
return rawToken.equals("(")
|
||||
&& (lastToken != null && !isOperator(lastToken) && !lastToken.equals("(") && !lastToken.equals(")"));
|
||||
}
|
||||
|
||||
private static String processToken(String input, String token, Deque<String> operators, Deque<Double> operands) {
|
||||
if (isOperator(token)) {
|
||||
popOperators(input, operators, operands,
|
||||
top -> (!top.equals("(") && getPrecedence(token) <= getPrecedence(top)));
|
||||
operators.push(token);
|
||||
} else if (token.equals("(")) {
|
||||
operators.push(token);
|
||||
} else if (token.equals(")")) {
|
||||
popOperators(input, operators, operands, top -> !top.equals("("));
|
||||
if (!operators.pop().equals("(")) {
|
||||
throw new IllegalArgumentException("Unbalanced right parentheses in expression: " + input);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
operands.push(Double.parseDouble(token));
|
||||
} catch (NumberFormatException exception) {
|
||||
throw new IllegalArgumentException("Could not parse double from:" + token);
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
private static void popOperators(String input, Deque<String> operators, Deque<Double> operands,
|
||||
Predicate<String> predicate) {
|
||||
try {
|
||||
while (!operators.isEmpty() && predicate.test(operators.peek())) {
|
||||
final String op = operators.pop();
|
||||
String op = operators.pop();
|
||||
if (op.equals("u")) {
|
||||
operands.push(-operands.pop());
|
||||
continue;
|
||||
@@ -96,8 +79,8 @@ public class EquationEvaluator {
|
||||
throw new IllegalArgumentException("Unexpected arithmetic operation " + op);
|
||||
}
|
||||
|
||||
private static boolean isOperator(String token) {
|
||||
switch (token) {
|
||||
private static boolean isOperator(String op) {
|
||||
switch (op) {
|
||||
case "+":
|
||||
case "-":
|
||||
case "*":
|
||||
|
@@ -61,17 +61,4 @@ class EquationEvaluatorTest {
|
||||
assertFuzzyEquals(1, EquationEvaluator.evaluate("1 - 2 + 3 * 4 / 6"));
|
||||
assertFuzzyEquals(4.0 / 3, EquationEvaluator.evaluate("(((1 - 2) + 3) * 4) / 6"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDivideByZero() {
|
||||
assertFuzzyEquals(Double.POSITIVE_INFINITY, EquationEvaluator.evaluate("1 / 0"));
|
||||
assertFuzzyEquals(Double.POSITIVE_INFINITY, EquationEvaluator.evaluate("1 / (1 - 1)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testImplicitMultiply() {
|
||||
assertFuzzyEquals(-2, EquationEvaluator.evaluate("2(3 + 6) - 5(6 - 2)"));
|
||||
assertFuzzyEquals(1, EquationEvaluator.evaluate("6 / (2(4 - 1))"));
|
||||
assertFuzzyEquals(6 * 5 * 4 * 3 * 2, EquationEvaluator.evaluate("6(5(4(3(2(1)))))"));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user