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.StringTokenizer;
import java.util.function.Predicate; import java.util.function.Predicate;
import javax.annotation.Nullable;
/** /**
* Implements evaluation for simple math expressions using the shunting yard * Implements evaluation for simple math expressions using the shunting yard
* algorithm. * algorithm.
@@ -15,36 +13,18 @@ import javax.annotation.Nullable;
public class EquationEvaluator { public class EquationEvaluator {
public static double evaluate(String input) { public static double evaluate(String input) {
final StringTokenizer tokens = new StringTokenizer(input, "+-*/()", true); StringTokenizer tokens = new StringTokenizer(input, "+-*/()", true);
final Deque<String> operators = new ArrayDeque<>(); Deque<String> operators = new ArrayDeque<>();
final Deque<Double> operands = new ArrayDeque<>(); Deque<Double> operands = new ArrayDeque<>();
String lastToken = null; String lastToken = null;
while (tokens.hasMoreTokens()) { while (tokens.hasMoreTokens()) {
String rawToken = tokens.nextToken().trim(); String rawToken = tokens.nextToken().trim();
if (rawToken.isEmpty()) if (rawToken.isEmpty())
continue; continue;
if (isUnaryMinus(rawToken, lastToken)) {
rawToken = "u";
} else if (isImplicitMultiply(rawToken, lastToken)) {
lastToken = processToken(input, "*", operators, operands);
}
lastToken = processToken(input, rawToken, operators, operands);
}
popOperators(input, operators, operands, top -> true);
return operands.pop();
}
private static boolean isUnaryMinus(String rawToken, @Nullable String lastToken) { boolean isUnaryMinus = rawToken.equals("-") && (lastToken == null
return rawToken.equals("-") || (!lastToken.equals("u") && isOperator(lastToken)) || lastToken.equals("("));
&& (lastToken == null || (isOperator(lastToken) && !lastToken.equals("u")) || lastToken.equals("(")); final String token = isUnaryMinus ? "u" : rawToken;
}
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)) { if (isOperator(token)) {
popOperators(input, operators, operands, popOperators(input, operators, operands,
top -> (!top.equals("(") && getPrecedence(token) <= getPrecedence(top))); top -> (!top.equals("(") && getPrecedence(token) <= getPrecedence(top)));
@@ -60,17 +40,20 @@ public class EquationEvaluator {
try { try {
operands.push(Double.parseDouble(token)); operands.push(Double.parseDouble(token));
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
throw new IllegalArgumentException("Could not parse double from:" + token); throw new IllegalArgumentException("Could not evaluate expression: " + input);
} }
} }
return token; lastToken = token;
}
popOperators(input, operators, operands, top -> true);
return operands.pop();
} }
private static void popOperators(String input, Deque<String> operators, Deque<Double> operands, private static void popOperators(String input, Deque<String> operators, Deque<Double> operands,
Predicate<String> predicate) { Predicate<String> predicate) {
try { try {
while (!operators.isEmpty() && predicate.test(operators.peek())) { while (!operators.isEmpty() && predicate.test(operators.peek())) {
final String op = operators.pop(); String op = operators.pop();
if (op.equals("u")) { if (op.equals("u")) {
operands.push(-operands.pop()); operands.push(-operands.pop());
continue; continue;
@@ -96,8 +79,8 @@ public class EquationEvaluator {
throw new IllegalArgumentException("Unexpected arithmetic operation " + op); throw new IllegalArgumentException("Unexpected arithmetic operation " + op);
} }
private static boolean isOperator(String token) { private static boolean isOperator(String op) {
switch (token) { switch (op) {
case "+": case "+":
case "-": case "-":
case "*": case "*":

View File

@@ -61,17 +61,4 @@ class EquationEvaluatorTest {
assertFuzzyEquals(1, EquationEvaluator.evaluate("1 - 2 + 3 * 4 / 6")); assertFuzzyEquals(1, EquationEvaluator.evaluate("1 - 2 + 3 * 4 / 6"));
assertFuzzyEquals(4.0 / 3, 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)))))"));
}
} }