aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLinnea Gräf <roman.graef@gmail.com>2023-10-18 16:12:19 +0200
committerGitHub <noreply@github.com>2023-10-18 16:12:19 +0200
commite0a2f5f5991048317f5c045feca084a1413c45fd (patch)
tree7e4e8795aa98e58d6df467598b82c1c53997c869 /src
parent5ad2c41fb936fbb9927aa0b73c73f93f9fd1c3a0 (diff)
downloadNotEnoughUpdates-e0a2f5f5991048317f5c045feca084a1413c45fd.tar.gz
NotEnoughUpdates-e0a2f5f5991048317f5c045feca084a1413c45fd.tar.bz2
NotEnoughUpdates-e0a2f5f5991048317f5c045feca084a1413c45fd.zip
Add calculator precision option (#882)
* Add calculator precision option * Fix loading of minecraft classes from some tests
Diffstat (limited to 'src')
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/separatesections/Misc.java12
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java59
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/commands/misc/MiscCommands.kt3
-rw-r--r--src/test/kotlin/io/github/moulberry/notenoughupdates/util/BootstrapHook.kt54
-rw-r--r--src/test/kotlin/io/github/moulberry/notenoughupdates/util/CalculatorTest.kt2
-rw-r--r--src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension20
7 files changed, 132 insertions, 20 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java
index 71dedb12..66b6d2d5 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java
@@ -48,7 +48,7 @@ public class NeuSearchCalculator {
lastInput = input;
try {
BigDecimal calculate = Calculator.calculate(input, PROVIDE_LOWEST_BIN);
- lastResult = new DecimalFormat("#,##0.##").format(calculate);
+ lastResult = Calculator.getDecimalFormat().format(calculate);
} catch (Calculator.CalculatorException ignored) {
lastResult = null;
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/separatesections/Misc.java b/src/main/java/io/github/moulberry/notenoughupdates/options/separatesections/Misc.java
index 72521821..a9a0856e 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/separatesections/Misc.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/separatesections/Misc.java
@@ -259,6 +259,18 @@ public class Misc {
@Expose
@ConfigOption(
+ name = "Calculator Precision",
+ desc = "Digits after the , to display in the calculator"
+ )
+ @ConfigEditorSlider(
+ minValue = 1,
+ maxValue = 100,
+ minStep = 1
+ )
+ public int calculationPrecision = 5;
+
+ @Expose
+ @ConfigOption(
name = "Enable Abiphone Warning",
desc = "Asks for confirmation when removing a contact in the abiphone"
)
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 2b741e94..6b6d0074 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java
@@ -19,8 +19,11 @@
package io.github.moulberry.notenoughupdates.util;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+
import java.math.BigDecimal;
import java.math.RoundingMode;
+import java.text.DecimalFormat;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
@@ -34,6 +37,14 @@ public class Calculator {
Optional<BigDecimal> provideVariable(String name) throws CalculatorException;
}
+ public static DecimalFormat getDecimalFormat() {
+ StringBuilder f = new StringBuilder("#,##0.");
+ for (int i = 0; i < NotEnoughUpdates.INSTANCE.config.misc.calculationPrecision; i++) {
+ f.append("#");
+ }
+ return new DecimalFormat(f.toString());
+ }
+
public static BigDecimal calculate(String source, VariableProvider variables) throws CalculatorException {
return evaluate(variables, shuntingYard(lex(source)));
}
@@ -269,6 +280,7 @@ public class Calculator {
///<editor-fold desc="Evaluating Time">
public static BigDecimal evaluate(VariableProvider provider, List<Token> rpnTokens) throws CalculatorException {
Deque<BigDecimal> values = new ArrayDeque<>();
+ int precision = NotEnoughUpdates.INSTANCE != null ? NotEnoughUpdates.INSTANCE.config.misc.calculationPrecision : 5;
try {
for (Token command : rpnTokens) {
switch (command.type) {
@@ -287,42 +299,54 @@ public class Calculator {
values.push(new BigDecimal(command.numericValue).scaleByPowerOfTen(command.exponent));
break;
case BINOP:
- BigDecimal right = values.pop().setScale(2, RoundingMode.HALF_UP);
- BigDecimal left = values.pop().setScale(2, RoundingMode.HALF_UP);
+ BigDecimal right = values.pop().setScale(precision, RoundingMode.HALF_UP);
+ BigDecimal left = values.pop().setScale(precision, 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);
+ 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);
+ throw new CalculatorException(
+ right + " has a decimal, pick a power that is non-decimal",
+ rightToken.tokenStart,
+ rightToken.tokenLength
+ );
}
if (right.doubleValue() < 0) {
Token rightToken = rpnTokens.get(rpnTokens.indexOf(command) - 1);
- throw new CalculatorException(right + " is a negative number, pick a power that is positive", rightToken.tokenStart, rightToken.tokenLength);
+ throw new CalculatorException(
+ right + " is a negative number, pick a power that is positive",
+ rightToken.tokenStart,
+ rightToken.tokenLength
+ );
}
- values.push(left.pow(right.intValue()).setScale(2, RoundingMode.HALF_UP));
+ values.push(left.pow(right.intValue()).setScale(precision, RoundingMode.HALF_UP));
break;
case "x":
case "*":
- values.push(left.multiply(right).setScale(2, RoundingMode.HALF_UP));
+ values.push(left.multiply(right).setScale(precision, RoundingMode.HALF_UP));
break;
case "/":
try {
- values.push(left.divide(right, RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP));
+ values.push(left.divide(right, RoundingMode.HALF_UP).setScale(precision, RoundingMode.HALF_UP));
} catch (ArithmeticException e) {
throw new CalculatorException("Encountered division by 0", command.tokenStart, command.tokenLength);
}
break;
case "+":
- values.push(left.add(right).setScale(2, RoundingMode.HALF_UP));
+ values.push(left.add(right).setScale(precision, RoundingMode.HALF_UP));
break;
case "-":
- values.push(left.subtract(right).setScale(2, RoundingMode.HALF_UP));
+ values.push(left.subtract(right).setScale(precision, RoundingMode.HALF_UP));
break;
default:
throw new CalculatorException(
@@ -343,22 +367,25 @@ public class Calculator {
BigDecimal p = values.pop();
switch (command.operatorValue.intern()) {
case "s":
- values.push(p.multiply(new BigDecimal(64)).setScale(2, RoundingMode.HALF_UP));
+ values.push(p.multiply(new BigDecimal(64)).setScale(precision, RoundingMode.HALF_UP));
break;
case "k":
- values.push(p.multiply(new BigDecimal(1_000)).setScale(2, RoundingMode.HALF_UP));
+ values.push(p.multiply(new BigDecimal(1_000)).setScale(precision, RoundingMode.HALF_UP));
break;
case "m":
- values.push(p.multiply(new BigDecimal(1_000_000)).setScale(2, RoundingMode.HALF_UP));
+ values.push(p.multiply(new BigDecimal(1_000_000)).setScale(precision, RoundingMode.HALF_UP));
break;
case "b":
- values.push(p.multiply(new BigDecimal(1_000_000_000)).setScale(2, RoundingMode.HALF_UP));
+ values.push(p.multiply(new BigDecimal(1_000_000_000)).setScale(precision, RoundingMode.HALF_UP));
break;
case "t":
- values.push(p.multiply(new BigDecimal("1000000000000")).setScale(2, RoundingMode.HALF_UP));
+ values.push(p.multiply(new BigDecimal("1000000000000")).setScale(precision, 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));
+ values.push(p
+ .setScale(precision + 1, RoundingMode.HALF_UP)
+ .divide(new BigDecimal(100), RoundingMode.HALF_UP)
+ .setScale(precision, RoundingMode.HALF_UP));
break;
default:
throw new CalculatorException(
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/misc/MiscCommands.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/misc/MiscCommands.kt
index 64ee444b..422871b4 100644
--- a/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/misc/MiscCommands.kt
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/misc/MiscCommands.kt
@@ -40,7 +40,6 @@ import net.minecraft.client.renderer.OpenGlHelper
import net.minecraft.util.ChatComponentText
import net.minecraft.util.EnumChatFormatting.*
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
-import java.text.DecimalFormat
import java.util.*
import java.util.concurrent.CompletableFuture
@@ -53,7 +52,7 @@ class MiscCommands {
val calculation = this[calculation]
try {
val calculate = Calculator.calculate(calculation, NeuSearchCalculator.PROVIDE_LOWEST_BIN)
- val formatter = DecimalFormat("#,##0.##")
+ val formatter = Calculator.getDecimalFormat()
val formatted = formatter.format(calculate)
reply("$WHITE$calculation $YELLOW= $GREEN$formatted")
} catch (e: CalculatorException) {
diff --git a/src/test/kotlin/io/github/moulberry/notenoughupdates/util/BootstrapHook.kt b/src/test/kotlin/io/github/moulberry/notenoughupdates/util/BootstrapHook.kt
new file mode 100644
index 00000000..cab10aaa
--- /dev/null
+++ b/src/test/kotlin/io/github/moulberry/notenoughupdates/util/BootstrapHook.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util
+
+import net.minecraft.block.Block
+import net.minecraft.block.BlockFire
+import net.minecraft.init.Bootstrap
+import net.minecraft.item.Item
+import org.junit.jupiter.api.extension.BeforeAllCallback
+import org.junit.jupiter.api.extension.Extension
+import org.junit.jupiter.api.extension.ExtensionContext
+import java.util.concurrent.locks.Lock
+import java.util.concurrent.locks.ReentrantLock
+
+class BootstrapHook : BeforeAllCallback, Extension {
+ companion object {
+ private val LOCK: Lock = ReentrantLock()
+ private var bootstrapped = false
+ }
+
+ override fun beforeAll(p0: ExtensionContext?) {
+ LOCK.lock()
+ try {
+ if (!bootstrapped) {
+ bootstrapped = true
+
+ Bootstrap::class.java.getDeclaredField("alreadyRegistered").also { it.isAccessible = true }
+ .set(null, true)
+ Block.registerBlocks()
+ BlockFire.init()
+ Item.registerItems()
+ }
+ } finally {
+ LOCK.unlock()
+ }
+ }
+}
diff --git a/src/test/kotlin/io/github/moulberry/notenoughupdates/util/CalculatorTest.kt b/src/test/kotlin/io/github/moulberry/notenoughupdates/util/CalculatorTest.kt
index ce866eec..6c4b1e1c 100644
--- a/src/test/kotlin/io/github/moulberry/notenoughupdates/util/CalculatorTest.kt
+++ b/src/test/kotlin/io/github/moulberry/notenoughupdates/util/CalculatorTest.kt
@@ -41,7 +41,7 @@ internal class CalculatorTest {
calculationShouldBe("(1)+1", 2)
calculationShouldBe("-0", 0)
calculationShouldBe("-10+2", -8)
- calculationShouldBe("14k*23m/2.35+596123-9213", 137021863505.74)
+ calculationShouldBe("14k*23m/2.35+596123-9213", 137021863505.74467)
calculationShouldBe("1+-10+2", -7)
calculationShouldBe("2**--10", 2.0.pow(10))
}
diff --git a/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension
new file mode 100644
index 00000000..6cc832b4
--- /dev/null
+++ b/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2023 NotEnoughUpdates contributors
+#
+# This file is part of NotEnoughUpdates.
+#
+# NotEnoughUpdates is free software: you can redistribute it
+# and/or modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation, either
+# version 3 of the License, or (at your option) any later version.
+#
+# NotEnoughUpdates is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+#
+
+io.github.moulberry.notenoughupdates.util.BootstrapHook