diff options
-rw-r--r-- | src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java index 10bfa6a9..b39a05f4 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java @@ -48,8 +48,8 @@ public class Calculator { int tokenLength; } - static String binops = "+-*/x"; - static String postops = "mkbts"; + static String binops = "+-*/^x"; + static String postops = "mkbts%"; static String digits = "0123456789"; static void readDigitsInto(Token token, String source, boolean decimals) { @@ -150,6 +150,8 @@ public class Calculator { case "/": case "x": return 1; + case "^": + return 2; } throw new CalculatorException("Unknown operator " + token.operatorValue, token.tokenStart, token.tokenLength); } @@ -160,6 +162,7 @@ public class Calculator { Deque<Token> op = new ArrayDeque<>(); List<Token> out = new ArrayList<>(); + boolean nextMultiplyShouldBePower = false; for (Token currentlyShunting : toShunt) { switch (currentlyShunting.type) { @@ -167,6 +170,17 @@ public class Calculator { out.add(currentlyShunting); break; case BINOP: + Token next = toShunt.get(toShunt.indexOf(currentlyShunting) + 1); + if (currentlyShunting.operatorValue.equals("^")) { + if (next.numericValue > 999) { + throw new CalculatorException(next.numericValue + " is too large, pick a power less than 1000", next.tokenStart, next.tokenLength); + } + } else if (next != null && currentlyShunting.operatorValue.equals("*") && next.operatorValue != null && next.operatorValue.equals("*")) { + nextMultiplyShouldBePower = true; + continue; + } else if (nextMultiplyShouldBePower && currentlyShunting.operatorValue.equals("*")) { + currentlyShunting.operatorValue = "^"; + } int p = getPrecedence(currentlyShunting); while (!op.isEmpty()) { Token l = op.peek(); @@ -230,6 +244,18 @@ public class Calculator { BigDecimal right = values.pop().setScale(2, RoundingMode.HALF_UP); BigDecimal left = values.pop().setScale(2, RoundingMode.HALF_UP); switch (command.operatorValue.intern()) { + case "^": + if (right.compareTo(new BigDecimal(1000)) >= 0) { + Token rightToken = rpnTokens.get(rpnTokens.indexOf(command) - 1); + throw new CalculatorException(right + " is too large, pick a power less than 1000", rightToken.tokenStart, rightToken.tokenLength); + } + + if (right.doubleValue() != right.intValue()) { + Token rightToken = rpnTokens.get(rpnTokens.indexOf(command) - 1); + throw new CalculatorException(right + " has a decimal, pick a power that is non-decimal", rightToken.tokenStart, rightToken.tokenLength); + } + values.push(left.pow(right.intValue()).setScale(2, RoundingMode.HALF_UP)); + break; case "x": case "*": values.push(left.multiply(right).setScale(2, RoundingMode.HALF_UP)); @@ -280,6 +306,9 @@ public class Calculator { case "t": values.push(p.multiply(new BigDecimal("1000000000000")).setScale(2, RoundingMode.HALF_UP)); break; + case "%": + values.push(p.setScale(3, RoundingMode.HALF_UP).divide(new BigDecimal(100), RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP)); + break; default: throw new CalculatorException( "Unknown operation " + command.operatorValue, |