Revert "Add support for implicit multiply in equations"

This reverts commit a218a8276b.
This commit is contained in:
raoulvdberge
2022-07-30 19:47:27 +02:00
parent 0afadf4dec
commit 1ea4e663f1
2 changed files with 28 additions and 58 deletions

View File

@@ -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 "*":

View File

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