Added test class for EquationEvaluator

This commit is contained in:
tastybento 2024-01-13 08:50:37 -08:00
parent 2b373f62d9
commit 76e0bad88a
2 changed files with 132 additions and 95 deletions

View File

@ -3,7 +3,7 @@ package world.bentobox.level.calculators;
import java.text.ParseException; import java.text.ParseException;
/** /**
* @author tastybento * Utility class to evaluate equations
*/ */
public class EquationEvaluator { public class EquationEvaluator {
@ -12,6 +12,11 @@ public class EquationEvaluator {
private int pos = -1; private int pos = -1;
private int currentChar; private int currentChar;
@SuppressWarnings("unused")
private Parser() {
throw new IllegalStateException("Utility class");
}
public Parser(String input) { public Parser(String input) {
this.input = input; this.input = input;
moveToNextChar(); moveToNextChar();
@ -22,8 +27,9 @@ public class EquationEvaluator {
} }
private boolean tryToEat(int charToEat) { private boolean tryToEat(int charToEat) {
while (currentChar == ' ') while (currentChar == ' ') {
moveToNextChar(); moveToNextChar();
}
if (currentChar == charToEat) { if (currentChar == charToEat) {
moveToNextChar(); moveToNextChar();
return true; return true;
@ -42,60 +48,54 @@ public class EquationEvaluator {
private double parseExpression() throws ParseException { private double parseExpression() throws ParseException {
double result = parseTerm(); double result = parseTerm();
while (true) { while (true) {
if (tryToEat('+')) if (tryToEat('+')) {
result += parseTerm(); result += parseTerm();
else if (tryToEat('-')) } else if (tryToEat('-')) {
result -= parseTerm(); result -= parseTerm();
else } else {
return result; return result;
} }
} }
}
private double parseFactor() throws ParseException { private double parseFactor() throws ParseException {
if (tryToEat('+')) if (tryToEat('+')) {
return parseFactor(); // unary plus return parseFactor(); // unary plus
if (tryToEat('-')) }
if (tryToEat('-')) {
return -parseFactor(); // unary minus return -parseFactor(); // unary minus
}
double x; double x;
int startPos = this.pos; int startPos = this.pos;
if (tryToEat('(')) { // parentheses if (tryToEat('(')) { // parentheses
x = parseExpression(); x = parseExpression();
tryToEat(')'); tryToEat(')');
} else if ((currentChar >= '0' && currentChar <= '9') || currentChar == '.') { // numbers } else if ((currentChar >= '0' && currentChar <= '9') || currentChar == '.') { // numbers
while ((currentChar >= '0' && currentChar <= '9') || currentChar == '.') while ((currentChar >= '0' && currentChar <= '9') || currentChar == '.') {
moveToNextChar(); moveToNextChar();
}
x = Double.parseDouble(input.substring(startPos, this.pos)); x = Double.parseDouble(input.substring(startPos, this.pos));
} else if (currentChar >= 'a' && currentChar <= 'z') { // functions } else if (currentChar >= 'a' && currentChar <= 'z') { // functions
while (currentChar >= 'a' && currentChar <= 'z') while (currentChar >= 'a' && currentChar <= 'z') {
moveToNextChar(); moveToNextChar();
}
String func = input.substring(startPos, this.pos); String func = input.substring(startPos, this.pos);
x = parseFactor(); x = parseFactor();
switch (func) { x = switch (func) {
case "sqrt": case "sqrt" -> Math.sqrt(x);
x = Math.sqrt(x); case "sin" -> Math.sin(Math.toRadians(x));
break; case "cos" -> Math.cos(Math.toRadians(x));
case "sin": case "tan" -> Math.tan(Math.toRadians(x));
x = Math.sin(Math.toRadians(x)); case "log" -> Math.log(x);
break; default -> throw new ParseException("Unknown function: " + func, startPos);
case "cos": };
x = Math.cos(Math.toRadians(x));
break;
case "tan":
x = Math.tan(Math.toRadians(x));
break;
case "log":
x = Math.log(x);
break;
default:
throw new ParseException("Unknown function: " + func, startPos);
}
} else { } else {
throw new ParseException("Unexpected: " + (char) currentChar, startPos); throw new ParseException("Unexpected: " + (char) currentChar, startPos);
} }
if (tryToEat('^')) if (tryToEat('^')) {
x = Math.pow(x, parseFactor()); // exponentiation x = Math.pow(x, parseFactor()); // exponentiation
}
return x; return x;
} }

View File

@ -0,0 +1,37 @@
package world.bentobox.level.calculators;
import static org.junit.Assert.assertEquals;
import java.text.ParseException;
import org.junit.Test;
/**
* Test the equation evaluation
*/
public class EquationEvaluatorTest {
/**
* Test method for {@link world.bentobox.level.calculators.EquationEvaluator#eval(java.lang.String)}.
* @throws ParseException
*/
@Test
public void testEval() throws ParseException {
assertEquals(4D, EquationEvaluator.eval("2+2"), 0D);
assertEquals(0D, EquationEvaluator.eval("2-2"), 0D);
assertEquals(1D, EquationEvaluator.eval("2/2"), 0D);
assertEquals(4D, EquationEvaluator.eval("2*2"), 0D);
assertEquals(8D, EquationEvaluator.eval("2+2+2+2"), 0D);
assertEquals(5D, EquationEvaluator.eval("2.5+2.5"), 0D);
assertEquals(1.414, EquationEvaluator.eval("sqrt(2)"), 0.001D);
assertEquals(3.414, EquationEvaluator.eval("2 + sqrt(2)"), 0.001D);
assertEquals(0D, EquationEvaluator.eval("sin(0)"), 0.1D);
assertEquals(1D, EquationEvaluator.eval("cos(0)"), 0.1D);
assertEquals(0D, EquationEvaluator.eval("tan(0)"), 0.1D);
assertEquals(0D, EquationEvaluator.eval("log(1)"), 0.1D);
assertEquals(27D, EquationEvaluator.eval("3^3"), 0.D);
assertEquals(84.70332D, EquationEvaluator.eval("3^3 + 2 + 2.65 * (3 / 4) - sin(45) * log(10) + 55.344"),
0.0001D);
}
}