1
0
mirror of https://github.com/DanilaFe/abacus synced 2026-01-26 00:25:20 +00:00

Compare commits

...

27 Commits

Author SHA1 Message Date
Arthur Drobot
7d5efa1fe6 Add fromInt function into StandardPlugin and replace existing instantiations and promotions of NaiveNumbers with integer values with fromInt calls. 2017-08-07 10:33:16 -07:00
arthur326
6a15c266c4 Fix typo in cot function. 2017-08-06 18:13:01 -07:00
9f61fc5dbe Remove the correct unused intPow function. 2017-08-05 18:23:24 -07:00
bae6ee5526 Revert "Remove the NumberInterface::intPow method."
0c16bb4e9b
2017-08-05 18:22:43 -07:00
4f94700aef Remove the NumberInterface::intPow method. 2017-08-05 18:11:16 -07:00
b7152da58d Merge branch 'stoppable-alternate' 2017-08-05 17:58:26 -07:00
d17a8a9fa7 Add missing javadoc. 2017-08-05 17:29:35 -07:00
71c9f0d141 Merge branch 'documentation' 2017-08-05 17:28:08 -07:00
fb02984e60 Decrease test intensity to prevent travis CI from killing gradle. 2017-08-05 17:24:16 -07:00
a9ac4681f0 Use a specific configuration instead of chancing it with a local file. 2017-08-05 17:13:03 -07:00
62d7053441 Get rid of unnecessary supplier. 2017-08-05 17:09:12 -07:00
f3cbb600ac Remove the default load-from-file behavior from the Abacus core. 2017-08-05 17:04:07 -07:00
abc0e2d59f Add tests for more complex functions. 2017-08-05 16:57:52 -07:00
f7d1be086b Add tests for basic operations. 2017-08-05 16:57:22 -07:00
21a925d6d2 Write two functions to help test the code. 2017-08-05 16:56:50 -07:00
0d21898f20 Make loading plugins a non-core part of Abacus, avoiding desktop APIs. 2017-08-05 16:21:02 -07:00
a984f2960d Prevent leaving unparsed tokens ignored, throwing error instead. 2017-08-05 16:01:08 -07:00
a6832e09f4 Fix mismatched parentheses causing exceptions. 2017-08-05 15:59:49 -07:00
0bcb3b25d9 Fix exception handling. 2017-08-05 15:58:43 -07:00
2f5f967be4 Add new comments. 2017-08-05 15:19:39 -07:00
72a2a8f1c1 Set output string correctly. 2017-08-05 14:43:24 -07:00
58fc94e9d0 Fix clearing input field. 2017-08-05 14:36:42 -07:00
9cedb100ad Re-introduce arthur326's fix for ln speed. 2017-08-05 14:34:57 -07:00
99be2d80f1 Run calculations via thread, and stop thread if necessary. 2017-08-05 14:34:31 -07:00
2523b9b04b Add a stop button. 2017-08-05 13:57:27 -07:00
cd60c9d52f Convert NumberInterface into abstract class, and check for interruption. 2017-08-05 13:54:06 -07:00
23a3eb88f1 Remove old stopping code. 2017-08-05 13:26:29 -07:00
15 changed files with 446 additions and 242 deletions

View File

@@ -6,16 +6,12 @@ import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.parsing.LexerTokenizer; import org.nwapw.abacus.parsing.LexerTokenizer;
import org.nwapw.abacus.parsing.ShuntingYardParser; import org.nwapw.abacus.parsing.ShuntingYardParser;
import org.nwapw.abacus.parsing.TreeBuilder; import org.nwapw.abacus.parsing.TreeBuilder;
import org.nwapw.abacus.plugin.ClassFinder;
import org.nwapw.abacus.plugin.NumberImplementation; import org.nwapw.abacus.plugin.NumberImplementation;
import org.nwapw.abacus.plugin.PluginManager; import org.nwapw.abacus.plugin.PluginManager;
import org.nwapw.abacus.plugin.StandardPlugin; import org.nwapw.abacus.plugin.StandardPlugin;
import org.nwapw.abacus.tree.NumberReducer; import org.nwapw.abacus.tree.NumberReducer;
import org.nwapw.abacus.tree.TreeNode; import org.nwapw.abacus.tree.TreeNode;
import java.io.File;
import java.io.IOException;
/** /**
* The main calculator class. This is responsible * The main calculator class. This is responsible
* for piecing together all of the components, allowing * for piecing together all of the components, allowing
@@ -27,10 +23,6 @@ public class Abacus {
* The default number implementation to be used if no other one is available / selected. * The default number implementation to be used if no other one is available / selected.
*/ */
public static final NumberImplementation DEFAULT_IMPLEMENTATION = StandardPlugin.IMPLEMENTATION_NAIVE; public static final NumberImplementation DEFAULT_IMPLEMENTATION = StandardPlugin.IMPLEMENTATION_NAIVE;
/**
* The file used for saving and loading configuration.
*/
public static final File CONFIG_FILE = new File("config.toml");
/** /**
* The plugin manager responsible for * The plugin manager responsible for
@@ -54,26 +46,19 @@ public class Abacus {
/** /**
* Creates a new instance of the Abacus calculator. * Creates a new instance of the Abacus calculator.
*
* @param configuration the configuration object for this Abacus instance.
*/ */
public Abacus() { public Abacus(Configuration configuration) {
pluginManager = new PluginManager(this); pluginManager = new PluginManager(this);
numberReducer = new NumberReducer(this); numberReducer = new NumberReducer(this);
configuration = new Configuration(CONFIG_FILE); this.configuration = new Configuration(configuration);
configuration.saveTo(CONFIG_FILE);
LexerTokenizer lexerTokenizer = new LexerTokenizer(); LexerTokenizer lexerTokenizer = new LexerTokenizer();
ShuntingYardParser shuntingYardParser = new ShuntingYardParser(this); ShuntingYardParser shuntingYardParser = new ShuntingYardParser(this);
treeBuilder = new TreeBuilder<>(lexerTokenizer, shuntingYardParser); treeBuilder = new TreeBuilder<>(lexerTokenizer, shuntingYardParser);
pluginManager.addListener(lexerTokenizer);
pluginManager.addListener(shuntingYardParser); pluginManager.addListener(shuntingYardParser);
pluginManager.addInstantiated(new StandardPlugin(pluginManager)); pluginManager.addListener(lexerTokenizer);
try {
ClassFinder.loadJars("plugins")
.forEach(plugin -> pluginManager.addClass(plugin));
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
pluginManager.load();
} }
public static void main(String[] args) { public static void main(String[] args) {

View File

@@ -39,6 +39,15 @@ public class Configuration {
*/ */
private Set<String> disabledPlugins = new HashSet<>(); private Set<String> disabledPlugins = new HashSet<>();
/**
* Creates a new configuration form the given configuration.
*
* @param copyFrom the configuration to copy.
*/
public Configuration(Configuration copyFrom){
copyFrom(copyFrom);
}
/** /**
* Creates a new configuration with the given values. * Creates a new configuration with the given values.
* *
@@ -85,6 +94,15 @@ public class Configuration {
} }
} }
/**
* Gets the value of this configuration as a string.
*
* @return the string that represents this configuration.
*/
public String asTomlString(){
return TOML_WRITER.write(this);
}
/** /**
* Gets the number implementation from this configuration. * Gets the number implementation from this configuration.
* *

View File

@@ -11,11 +11,16 @@ import javafx.util.Callback;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import org.nwapw.abacus.Abacus; import org.nwapw.abacus.Abacus;
import org.nwapw.abacus.config.Configuration; import org.nwapw.abacus.config.Configuration;
import org.nwapw.abacus.number.ComputationInterruptedException;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.plugin.ClassFinder;
import org.nwapw.abacus.plugin.PluginListener; import org.nwapw.abacus.plugin.PluginListener;
import org.nwapw.abacus.plugin.PluginManager; import org.nwapw.abacus.plugin.PluginManager;
import org.nwapw.abacus.plugin.StandardPlugin;
import org.nwapw.abacus.tree.TreeNode; import org.nwapw.abacus.tree.TreeNode;
import java.io.File;
import java.io.IOException;
import java.util.Set; import java.util.Set;
@@ -25,6 +30,10 @@ import java.util.Set;
*/ */
public class AbacusController implements PluginListener { public class AbacusController implements PluginListener {
/**
* The file used for saving and loading configuration.
*/
public static final File CONFIG_FILE = new File("config.toml");
/** /**
* The title for the apply alert dialog. * The title for the apply alert dialog.
*/ */
@@ -50,6 +59,10 @@ public class AbacusController implements PluginListener {
* Constant string that is displayed if the calculations are stopped before they are done. * Constant string that is displayed if the calculations are stopped before they are done.
*/ */
private static final String ERR_STOP = "Stopped"; private static final String ERR_STOP = "Stopped";
/**
* Constant string that is displayed if the calculations are interrupted by an exception.
*/
private static final String ERR_EXCEPTION = "Exception Thrown";
@FXML @FXML
private TabPane coreTabPane; private TabPane coreTabPane;
@FXML @FXML
@@ -71,6 +84,8 @@ public class AbacusController implements PluginListener {
@FXML @FXML
private Button inputButton; private Button inputButton;
@FXML @FXML
private Button stopButton;
@FXML
private ComboBox<String> numberImplementationBox; private ComboBox<String> numberImplementationBox;
@FXML @FXML
private ListView<ToggleablePlugin> enabledPluginView; private ListView<ToggleablePlugin> enabledPluginView;
@@ -87,7 +102,6 @@ public class AbacusController implements PluginListener {
private ObservableList<String> numberImplementationOptions; private ObservableList<String> numberImplementationOptions;
/** /**
* <<<<<<< HEAD
* The list of plugin objects that can be toggled on and off, * The list of plugin objects that can be toggled on and off,
* and, when reloaded, get added to the plugin manager's black list. * and, when reloaded, get added to the plugin manager's black list.
*/ */
@@ -97,20 +111,6 @@ public class AbacusController implements PluginListener {
* The abacus instance used for changing the plugin configuration. * The abacus instance used for changing the plugin configuration.
*/ */
private Abacus abacus; private Abacus abacus;
/**
* Thread used for calculating.
*/
private Thread calcThread;
/**
* Checks whether the calculator is calculating.
*/
private boolean calculating;
/**
* Seconds delayed for timer;
*/
private double delay = 0;
/** /**
* Boolean which represents whether changes were made to the configuration. * Boolean which represents whether changes were made to the configuration.
@@ -124,6 +124,47 @@ public class AbacusController implements PluginListener {
* The alert shown when a press to "apply" is needed. * The alert shown when a press to "apply" is needed.
*/ */
private Alert reloadAlert; private Alert reloadAlert;
/**
* The runnable used to perform the calculation.
*/
private final Runnable CALCULATION_RUNNABLE = new Runnable() {
private String attemptCalculation(){
try {
TreeNode constructedTree = abacus.parseString(inputField.getText());
if (constructedTree == null) {
return ERR_SYNTAX;
}
NumberInterface evaluatedNumber = abacus.evaluateTree(constructedTree);
if (evaluatedNumber == null) {
return ERR_EVAL;
}
String resultingString = evaluatedNumber.toString();
historyData.add(new HistoryModel(inputField.getText(), constructedTree.toString(), resultingString));
return resultingString;
} catch (ComputationInterruptedException exception) {
return ERR_STOP;
} catch (RuntimeException exception){
exception.printStackTrace();
return ERR_EXCEPTION;
}
}
@Override
public void run() {
String calculation = attemptCalculation();
Platform.runLater(() -> {
outputText.setText(calculation);
inputField.setText("");
inputButton.setDisable(false);
stopButton.setDisable(true);
});
}
};
/**
* The thread in which the computation runs.
*/
private Thread calculationThread;
/** /**
* Alerts the user if the changes they made * Alerts the user if the changes they made
@@ -172,9 +213,16 @@ public class AbacusController implements PluginListener {
if (oldValue.equals(settingsTab)) alertIfApplyNeeded(true); if (oldValue.equals(settingsTab)) alertIfApplyNeeded(true);
}); });
abacus = new Abacus(); abacus = new Abacus(new Configuration(CONFIG_FILE));
abacus.getPluginManager().addListener(this); PluginManager abacusPluginManager = abacus.getPluginManager();
abacus.getPluginManager().reload(); abacusPluginManager.addListener(this);
abacusPluginManager.addInstantiated(new StandardPlugin(abacus.getPluginManager()));
try {
ClassFinder.loadJars("plugins").forEach(abacusPluginManager::addClass);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
abacusPluginManager.reload();
changesMade = false; changesMade = false;
reloadAlertShown = false; reloadAlertShown = false;
@@ -187,63 +235,16 @@ public class AbacusController implements PluginListener {
@FXML @FXML
private void performCalculation() { private void performCalculation() {
Runnable calculator = new Runnable() { inputButton.setDisable(true);
public void run() { stopButton.setDisable(false);
if (delay > 0) { calculationThread = new Thread(CALCULATION_RUNNABLE);
Runnable timer = new Runnable() { calculationThread.start();
public void run() {
long gap = (long) (delay * 1000);
long startTime = System.currentTimeMillis();
while (System.currentTimeMillis() - startTime <= gap) {
}
stopCalculation();
}
};
Thread maxTime = new Thread(timer);
maxTime.setName("maxTime");
maxTime.start();
}
calculating = true;
Platform.runLater(() -> inputButton.setDisable(true));
TreeNode constructedTree = abacus.parseString(inputField.getText());
if (constructedTree == null) {
Platform.runLater(() -> outputText.setText(ERR_SYNTAX));
Platform.runLater(() -> inputButton.setDisable(false));
//return;
} else {
NumberInterface evaluatedNumber = abacus.evaluateTree(constructedTree);
if (evaluatedNumber == null) {
if (Thread.currentThread().isInterrupted()) {
Platform.runLater(() -> outputText.setText(ERR_STOP));
Platform.runLater(() -> inputButton.setDisable(false));
} else {
Platform.runLater(() -> outputText.setText(ERR_EVAL));
Platform.runLater(() -> inputButton.setDisable(false));
//return;
}
} else {
Platform.runLater(() -> outputText.setText(evaluatedNumber.toString()));
historyData.add(new HistoryModel(inputField.getText(), constructedTree.toString(), evaluatedNumber.toString()));
Platform.runLater(() -> inputButton.setDisable(false));
Platform.runLater(() -> inputField.setText(""));
}
}
calculating = false;
}
};
if (!calculating) {
calcThread = new Thread(calculator);
calcThread.setName("calcThread");
calcThread.start();
}
} }
@FXML @FXML
private void stopCalculation() { private void performStop(){
calcThread.interrupt(); if(calculationThread != null)
calculating = false; calculationThread.interrupt();
//Platform.runLater(() ->inputButton.setDisable(false));
} }
@FXML @FXML
@@ -269,7 +270,7 @@ public class AbacusController implements PluginListener {
for (ToggleablePlugin pluginEntry : enabledPlugins) { for (ToggleablePlugin pluginEntry : enabledPlugins) {
if (!pluginEntry.isEnabled()) disabledPlugins.add(pluginEntry.getClassName()); if (!pluginEntry.isEnabled()) disabledPlugins.add(pluginEntry.getClassName());
} }
configuration.saveTo(Abacus.CONFIG_FILE); configuration.saveTo(CONFIG_FILE);
changesMade = false; changesMade = false;
reloadAlertShown = false; reloadAlertShown = false;
} }

View File

@@ -0,0 +1,16 @@
package org.nwapw.abacus.number;
/**
* Exception thrown when the computation is interrupted by
* the user.
*/
public class ComputationInterruptedException extends RuntimeException {
/**
* Creates a new exception of this type.
*/
public ComputationInterruptedException(){
super("Computation interrupted by user.");
}
}

View File

@@ -3,7 +3,7 @@ package org.nwapw.abacus.number;
/** /**
* An implementation of NumberInterface using a double. * An implementation of NumberInterface using a double.
*/ */
public class NaiveNumber implements NumberInterface { public class NaiveNumber extends NumberInterface {
/** /**
* The number zero. * The number zero.
@@ -42,32 +42,32 @@ public class NaiveNumber implements NumberInterface {
} }
@Override @Override
public NumberInterface multiply(NumberInterface multiplier) { public NumberInterface multiplyInternal(NumberInterface multiplier) {
return new NaiveNumber(value * ((NaiveNumber) multiplier).value); return new NaiveNumber(value * ((NaiveNumber) multiplier).value);
} }
@Override @Override
public NumberInterface divide(NumberInterface divisor) { public NumberInterface divideInternal(NumberInterface divisor) {
return new NaiveNumber(value / ((NaiveNumber) divisor).value); return new NaiveNumber(value / ((NaiveNumber) divisor).value);
} }
@Override @Override
public NumberInterface add(NumberInterface summand) { public NumberInterface addInternal(NumberInterface summand) {
return new NaiveNumber(value + ((NaiveNumber) summand).value); return new NaiveNumber(value + ((NaiveNumber) summand).value);
} }
@Override @Override
public NumberInterface subtract(NumberInterface subtrahend) { public NumberInterface subtractInternal(NumberInterface subtrahend) {
return new NaiveNumber(value - ((NaiveNumber) subtrahend).value); return new NaiveNumber(value - ((NaiveNumber) subtrahend).value);
} }
@Override @Override
public NumberInterface negate() { public NumberInterface negateInternal() {
return new NaiveNumber(-value); return new NaiveNumber(-value);
} }
@Override @Override
public NumberInterface intPow(int exponent) { public NumberInterface intPowInternal(int exponent) {
if (exponent == 0) { if (exponent == 0) {
return NaiveNumber.ONE; return NaiveNumber.ONE;
} }
@@ -95,17 +95,17 @@ public class NaiveNumber implements NumberInterface {
} }
@Override @Override
public NumberInterface ceiling() { public NumberInterface ceilingInternal() {
return new NaiveNumber(Math.ceil(value)); return new NaiveNumber(Math.ceil(value));
} }
@Override @Override
public NumberInterface floor() { public NumberInterface floorInternal() {
return new NaiveNumber(Math.floor(value)); return new NaiveNumber(Math.floor(value));
} }
@Override @Override
public NumberInterface fractionalPart() { public NumberInterface fractionalPartInternal() {
return new NaiveNumber(value - Math.floor(value)); return new NaiveNumber(value - Math.floor(value));
} }
@@ -115,7 +115,7 @@ public class NaiveNumber implements NumberInterface {
} }
@Override @Override
public NumberInterface promoteTo(Class<? extends NumberInterface> toClass) { public NumberInterface promoteToInternal(Class<? extends NumberInterface> toClass) {
if (toClass == this.getClass()) return this; if (toClass == this.getClass()) return this;
else if (toClass == PreciseNumber.class) { else if (toClass == PreciseNumber.class) {
return new PreciseNumber(Double.toString(value)); return new PreciseNumber(Double.toString(value));

View File

@@ -3,14 +3,22 @@ package org.nwapw.abacus.number;
/** /**
* An interface used to represent a number. * An interface used to represent a number.
*/ */
public interface NumberInterface { public abstract class NumberInterface {
/**
* Check if the thread was interrupted and
* throw an exception to end the computation.
*/
private static void checkInterrupted(){
if(Thread.currentThread().isInterrupted())
throw new ComputationInterruptedException();
}
/** /**
* The maximum precision to which this number operates. * The maximum precision to which this number operates.
* *
* @return the precision. * @return the precision.
*/ */
int getMaxPrecision(); public abstract int getMaxPrecision();
/** /**
* Multiplies this number by another, returning * Multiplies this number by another, returning
@@ -19,7 +27,21 @@ public interface NumberInterface {
* @param multiplier the multiplier * @param multiplier the multiplier
* @return the result of the multiplication. * @return the result of the multiplication.
*/ */
NumberInterface multiply(NumberInterface multiplier); protected abstract NumberInterface multiplyInternal(NumberInterface multiplier);
/**
* Multiplies this number by another, returning
* a new number instance. Also, checks if the
* thread has been interrupted, and if so, throws
* an exception.
*
* @param multiplier the multiplier
* @return the result of the multiplication.
*/
public final NumberInterface multiply(NumberInterface multiplier){
checkInterrupted();
return multiplyInternal(multiplier);
}
/** /**
* Divides this number by another, returning * Divides this number by another, returning
@@ -28,7 +50,21 @@ public interface NumberInterface {
* @param divisor the divisor * @param divisor the divisor
* @return the result of the division. * @return the result of the division.
*/ */
NumberInterface divide(NumberInterface divisor); protected abstract NumberInterface divideInternal(NumberInterface divisor);
/**
* Divides this number by another, returning
* a new number instance. Also, checks if the
* thread has been interrupted, and if so, throws
* an exception.
*
* @param divisor the divisor
* @return the result of the division.
*/
public final NumberInterface divide(NumberInterface divisor){
checkInterrupted();
return divideInternal(divisor);
}
/** /**
* Adds this number to another, returning * Adds this number to another, returning
@@ -37,7 +73,21 @@ public interface NumberInterface {
* @param summand the summand * @param summand the summand
* @return the result of the summation. * @return the result of the summation.
*/ */
NumberInterface add(NumberInterface summand); protected abstract NumberInterface addInternal(NumberInterface summand);
/**
* Adds this number to another, returning
* a new number instance. Also, checks if the
* thread has been interrupted, and if so, throws
* an exception.
*
* @param summand the summand
* @return the result of the summation.
*/
public final NumberInterface add(NumberInterface summand){
checkInterrupted();
return addInternal(summand);
}
/** /**
* Subtracts another number from this number, * Subtracts another number from this number,
@@ -46,7 +96,21 @@ public interface NumberInterface {
* @param subtrahend the subtrahend. * @param subtrahend the subtrahend.
* @return the result of the subtraction. * @return the result of the subtraction.
*/ */
NumberInterface subtract(NumberInterface subtrahend); protected abstract NumberInterface subtractInternal(NumberInterface subtrahend);
/**
* Subtracts another number from this number,
* a new number instance. Also, checks if the
* thread has been interrupted, and if so, throws
* an exception.
*
* @param subtrahend the subtrahend.
* @return the result of the subtraction.
*/
public final NumberInterface subtract(NumberInterface subtrahend){
checkInterrupted();
return subtractInternal(subtrahend);
}
/** /**
* Returns a new instance of this number with * Returns a new instance of this number with
@@ -54,7 +118,21 @@ public interface NumberInterface {
* *
* @return the new instance. * @return the new instance.
*/ */
NumberInterface negate(); protected abstract NumberInterface negateInternal();
/**
* Returns a new instance of this number with
* the sign flipped. Also, checks if the
* thread has been interrupted, and if so, throws
* an exception.
*
* @return the new instance.
*/
public final NumberInterface negate(){
checkInterrupted();
return negateInternal();
}
/** /**
* Raises this number to an integer power. * Raises this number to an integer power.
@@ -62,7 +140,20 @@ public interface NumberInterface {
* @param exponent the exponent to which to take the number. * @param exponent the exponent to which to take the number.
* @return the resulting value. * @return the resulting value.
*/ */
NumberInterface intPow(int exponent); protected abstract NumberInterface intPowInternal(int exponent);
/**
* Raises this number to an integer power. Also, checks if the
* thread has been interrupted, and if so, throws
* an exception.
*
* @param exponent the exponent to which to take the number.
* @return the resulting value.
*/
public final NumberInterface intPow(int exponent){
checkInterrupted();
return intPowInternal(exponent);
}
/** /**
* Compares this number to another. * Compares this number to another.
@@ -70,35 +161,70 @@ public interface NumberInterface {
* @param number the number to compare to. * @param number the number to compare to.
* @return same as Integer.compare(); * @return same as Integer.compare();
*/ */
int compareTo(NumberInterface number); public abstract int compareTo(NumberInterface number);
/** /**
* Same as Math.signum(). * Same as Math.signum().
* *
* @return 1 if this number is positive, -1 if this number is negative, 0 if this number is 0. * @return 1 if this number is positive, -1 if this number is negative, 0 if this number is 0.
*/ */
int signum(); public abstract int signum();
/** /**
* Returns the least integer greater than or equal to the number. * Returns the least integer greater than or equal to the number.
* *
* @return the least integer >= the number, if int can hold the value.
*/
protected abstract NumberInterface ceilingInternal();
/**
* Returns the least integer greater than or equal to the number.
* Also, checks if the thread has been interrupted, and if so, throws
* an exception.
*
* @return the least integer bigger or equal to the number, if int can hold the value. * @return the least integer bigger or equal to the number, if int can hold the value.
*/ */
NumberInterface ceiling(); public final NumberInterface ceiling(){
checkInterrupted();
return ceilingInternal();
}
/** /**
* Return the greatest integer less than or equal to the number. * Return the greatest integer less than or equal to the number.
* *
* @return the greatest integer smaller or equal the number, if int can hold the value. * @return the greatest integer smaller or equal the number, if int can hold the value.
*/ */
NumberInterface floor(); protected abstract NumberInterface floorInternal();
/**
* Return the greatest integer less than or equal to the number.
* Also, checks if the thread has been interrupted, and if so, throws
* an exception.
*
* @return the greatest int >= the number, if int can hold the value.
*/
public final NumberInterface floor(){
checkInterrupted();
return floorInternal();
}
/** /**
* Returns the fractional part of the number. * Returns the fractional part of the number.
* *
* @return the fractional part of the number. * @return the fractional part of the number.
*/ */
NumberInterface fractionalPart(); protected abstract NumberInterface fractionalPartInternal();
/**
* Returns the fractional part of the number.
* Also, checks if the thread has been interrupted,
* and if so, throws an exception.
* @return the fractional part of the number.
*/
public final NumberInterface fractionalPart(){
checkInterrupted();
return fractionalPartInternal();
}
/** /**
* Returns the integer representation of this number, discarding any fractional part, * Returns the integer representation of this number, discarding any fractional part,
@@ -106,7 +232,7 @@ public interface NumberInterface {
* *
* @return the integer value of this number. * @return the integer value of this number.
*/ */
int intValue(); public abstract int intValue();
/** /**
* Promotes this class to another number class. * Promotes this class to another number class.
@@ -114,6 +240,19 @@ public interface NumberInterface {
* @param toClass the class to promote to. * @param toClass the class to promote to.
* @return the resulting new instance. * @return the resulting new instance.
*/ */
NumberInterface promoteTo(Class<? extends NumberInterface> toClass); protected abstract NumberInterface promoteToInternal(Class<? extends NumberInterface> toClass);
/**
* Promotes this class to another number class. Also, checks if the
* thread has been interrupted, and if so, throws
* an exception.
*
* @param toClass the class to promote to.
* @return the resulting new instance.
*/
public final NumberInterface promoteTo(Class<? extends NumberInterface> toClass) {
checkInterrupted();
return promoteToInternal(toClass);
}
} }

View File

@@ -7,7 +7,7 @@ import java.math.RoundingMode;
* A number that uses a BigDecimal to store its value, * A number that uses a BigDecimal to store its value,
* leading to infinite possible precision. * leading to infinite possible precision.
*/ */
public class PreciseNumber implements NumberInterface { public class PreciseNumber extends NumberInterface {
/** /**
* The number one. * The number one.
@@ -52,27 +52,27 @@ public class PreciseNumber implements NumberInterface {
} }
@Override @Override
public NumberInterface multiply(NumberInterface multiplier) { public NumberInterface multiplyInternal(NumberInterface multiplier) {
return new PreciseNumber(this.value.multiply(((PreciseNumber) multiplier).value)); return new PreciseNumber(this.value.multiply(((PreciseNumber) multiplier).value));
} }
@Override @Override
public NumberInterface divide(NumberInterface divisor) { public NumberInterface divideInternal(NumberInterface divisor) {
return new PreciseNumber(value.divide(((PreciseNumber) divisor).value, this.getMaxPrecision(), RoundingMode.HALF_UP)); return new PreciseNumber(value.divide(((PreciseNumber) divisor).value, this.getMaxPrecision(), RoundingMode.HALF_UP));
} }
@Override @Override
public NumberInterface add(NumberInterface summand) { public NumberInterface addInternal(NumberInterface summand) {
return new PreciseNumber(value.add(((PreciseNumber) summand).value)); return new PreciseNumber(value.add(((PreciseNumber) summand).value));
} }
@Override @Override
public NumberInterface subtract(NumberInterface subtrahend) { public NumberInterface subtractInternal(NumberInterface subtrahend) {
return new PreciseNumber(value.subtract(((PreciseNumber) subtrahend).value)); return new PreciseNumber(value.subtract(((PreciseNumber) subtrahend).value));
} }
@Override @Override
public NumberInterface intPow(int exponent) { public NumberInterface intPowInternal(int exponent) {
if (exponent == 0) { if (exponent == 0) {
return PreciseNumber.ONE; return PreciseNumber.ONE;
} }
@@ -99,7 +99,7 @@ public class PreciseNumber implements NumberInterface {
} }
@Override @Override
public NumberInterface ceiling() { public NumberInterface ceilingInternal() {
String str = value.toPlainString(); String str = value.toPlainString();
int decimalIndex = str.indexOf('.'); int decimalIndex = str.indexOf('.');
if (decimalIndex != -1) { if (decimalIndex != -1) {
@@ -109,7 +109,7 @@ public class PreciseNumber implements NumberInterface {
} }
@Override @Override
public NumberInterface floor() { public NumberInterface floorInternal() {
String str = value.toPlainString(); String str = value.toPlainString();
int decimalIndex = str.indexOf('.'); int decimalIndex = str.indexOf('.');
if (decimalIndex != -1) { if (decimalIndex != -1) {
@@ -119,7 +119,7 @@ public class PreciseNumber implements NumberInterface {
} }
@Override @Override
public NumberInterface fractionalPart() { public NumberInterface fractionalPartInternal() {
String str = value.toPlainString(); String str = value.toPlainString();
int decimalIndex = str.indexOf('.'); int decimalIndex = str.indexOf('.');
if (decimalIndex != -1) { if (decimalIndex != -1) {
@@ -134,12 +134,12 @@ public class PreciseNumber implements NumberInterface {
} }
@Override @Override
public NumberInterface negate() { public NumberInterface negateInternal() {
return new PreciseNumber(value.negate()); return new PreciseNumber(value.negate());
} }
@Override @Override
public NumberInterface promoteTo(Class<? extends NumberInterface> toClass) { public NumberInterface promoteToInternal(Class<? extends NumberInterface> toClass) {
if (toClass == this.getClass()) { if (toClass == this.getClass()) {
return this; return this;
} }

View File

@@ -162,8 +162,10 @@ public class ShuntingYardParser implements Parser<Match<TokenType>>, PluginListe
@Override @Override
public TreeNode constructTree(List<Match<TokenType>> tokens) { public TreeNode constructTree(List<Match<TokenType>> tokens) {
tokens = intoPostfix(new ArrayList<>(tokens)); tokens = intoPostfix(new ArrayList<>(tokens));
if(tokens == null) return null;
Collections.reverse(tokens); Collections.reverse(tokens);
return constructRecursive(tokens); TreeNode constructedTree = constructRecursive(tokens);
return tokens.size() == 0 ? constructedTree : null;
} }
@Override @Override

View File

@@ -18,6 +18,11 @@ import java.util.function.BiFunction;
*/ */
public class StandardPlugin extends Plugin { public class StandardPlugin extends Plugin {
/**
* Stores objects of NumberInterface with integer values for reuse.
*/
private final static HashMap<Class<? extends NumberInterface>, HashMap<Integer, NumberInterface>> integerValues = new HashMap<>();
/** /**
* The addition operator, + * The addition operator, +
*/ */
@@ -29,13 +34,9 @@ public class StandardPlugin extends Plugin {
@Override @Override
protected NumberInterface applyInternal(NumberInterface[] params) { protected NumberInterface applyInternal(NumberInterface[] params) {
if (Thread.currentThread().isInterrupted())
return null;
NumberInterface sum = params[0]; NumberInterface sum = params[0];
for (int i = 1; i < params.length; i++) { for (int i = 1; i < params.length; i++) {
sum = sum.add(params[i]); sum = sum.add(params[i]);
if (Thread.currentThread().isInterrupted())
return null;
} }
return sum; return sum;
} }
@@ -51,8 +52,6 @@ public class StandardPlugin extends Plugin {
@Override @Override
protected NumberInterface applyInternal(NumberInterface[] params) { protected NumberInterface applyInternal(NumberInterface[] params) {
if (Thread.currentThread().isInterrupted())
return null;
return params[0].subtract(params[1]); return params[0].subtract(params[1]);
} }
@@ -68,8 +67,6 @@ public class StandardPlugin extends Plugin {
@Override @Override
protected NumberInterface applyInternal(NumberInterface[] params) { protected NumberInterface applyInternal(NumberInterface[] params) {
if (Thread.currentThread().isInterrupted())
return null;
return params[0].negate(); return params[0].negate();
} }
}); });
@@ -84,13 +81,9 @@ public class StandardPlugin extends Plugin {
@Override @Override
protected NumberInterface applyInternal(NumberInterface[] params) { protected NumberInterface applyInternal(NumberInterface[] params) {
if (Thread.currentThread().isInterrupted())
return null;
NumberInterface product = params[0]; NumberInterface product = params[0];
for (int i = 1; i < params.length; i++) { for (int i = 1; i < params.length; i++) {
product = product.multiply(params[i]); product = product.multiply(params[i]);
if (Thread.currentThread().isInterrupted())
return null;
} }
return product; return product;
} }
@@ -106,8 +99,6 @@ public class StandardPlugin extends Plugin {
@Override @Override
protected NumberInterface applyInternal(NumberInterface[] params) { protected NumberInterface applyInternal(NumberInterface[] params) {
if (Thread.currentThread().isInterrupted())
return null;
return params[0].divide(params[1]); return params[0].divide(params[1]);
} }
}); });
@@ -125,19 +116,15 @@ public class StandardPlugin extends Plugin {
@Override @Override
protected NumberInterface applyInternal(NumberInterface[] params) { protected NumberInterface applyInternal(NumberInterface[] params) {
if (Thread.currentThread().isInterrupted())
return null;
if (params[0].signum() == 0) { if (params[0].signum() == 0) {
return (new NaiveNumber(1)).promoteTo(params[0].getClass()); return fromInt(params[0].getClass(), 1);
} }
NumberInterface factorial = params[0]; NumberInterface factorial = params[0];
NumberInterface multiplier = params[0]; NumberInterface multiplier = params[0];
//It is necessary to later prevent calls of factorial on anything but non-negative integers. //It is necessary to later prevent calls of factorial on anything but non-negative integers.
while (!Thread.currentThread().isInterrupted() && (multiplier = multiplier.subtract(NaiveNumber.ONE.promoteTo(multiplier.getClass()))) != null && multiplier.signum() == 1) { while ((multiplier = multiplier.subtract(NaiveNumber.ONE.promoteTo(multiplier.getClass()))).signum() == 1) {
factorial = factorial.multiply(multiplier); factorial = factorial.multiply(multiplier);
} }
if (Thread.currentThread().isInterrupted())
return null;
return factorial; return factorial;
/*if(!storedList.containsKey(params[0].getClass())){ /*if(!storedList.containsKey(params[0].getClass())){
storedList.put(params[0].getClass(), new ArrayList<NumberInterface>()); storedList.put(params[0].getClass(), new ArrayList<NumberInterface>());
@@ -157,8 +144,6 @@ public class StandardPlugin extends Plugin {
@Override @Override
protected NumberInterface applyInternal(NumberInterface[] params) { protected NumberInterface applyInternal(NumberInterface[] params) {
if (Thread.currentThread().isInterrupted())
return null;
return params[0].multiply((new NaiveNumber(params[0].signum())).promoteTo(params[0].getClass())); return params[0].multiply((new NaiveNumber(params[0].signum())).promoteTo(params[0].getClass()));
} }
}; };
@@ -173,32 +158,26 @@ public class StandardPlugin extends Plugin {
@Override @Override
protected NumberInterface applyInternal(NumberInterface[] params) { protected NumberInterface applyInternal(NumberInterface[] params) {
if (Thread.currentThread().isInterrupted())
return null;
NumberInterface param = params[0]; NumberInterface param = params[0];
int powersOf2 = 0; int powersOf2 = 0;
NumberInterface check; while (FUNCTION_ABS.apply(param.subtract(NaiveNumber.ONE.promoteTo(param.getClass()))).compareTo(new NaiveNumber(0.1).promoteTo(param.getClass())) >= 0) {
while (!Thread.currentThread().isInterrupted() && (check = FUNCTION_ABS.apply(param.subtract(NaiveNumber.ONE.promoteTo(param.getClass())))) != null && (check.compareTo((new NaiveNumber(0.1)).promoteTo(param.getClass()))) >= 0) { if (param.subtract(NaiveNumber.ONE.promoteTo(param.getClass())).signum() == 1) {
if ((check = param.subtract(NaiveNumber.ONE.promoteTo(param.getClass()))) != null && check.signum() == 1) { param = param.divide(fromInt(param.getClass(), 2));
param = param.divide(new NaiveNumber(2).promoteTo(param.getClass()));
powersOf2++; powersOf2++;
if ((check = param.subtract(NaiveNumber.ONE.promoteTo(param.getClass()))) == null || check.signum() != 1) { if (param.subtract(NaiveNumber.ONE.promoteTo(param.getClass())).signum() != 1) {
break; break;
//No infinite loop for you. //No infinite loop for you.
} }
} else { } else {
param = param.multiply(new NaiveNumber(2).promoteTo(param.getClass())); param = param.multiply(fromInt(param.getClass(), 2));
powersOf2--; powersOf2--;
if ((check = param.subtract(NaiveNumber.ONE.promoteTo(param.getClass()))) == null || check.signum() != 1) { if (param.subtract(NaiveNumber.ONE.promoteTo(param.getClass())).signum() != -1) {
break; break;
//No infinite loop for you. //No infinite loop for you.
} }
} }
} }
NumberInterface check2; return getLog2(param).multiply((new NaiveNumber(powersOf2)).promoteTo(param.getClass())).add(getLogPartialSum(param));
if (!Thread.currentThread().isInterrupted() && (check = getLog2(param)) != null && (check = check.multiply((new NaiveNumber(powersOf2).promoteTo(param.getClass())))) != null && (check2 = getLogPartialSum(param)) != null && (check = check.add(check2)) != null)
return check;
return null;
} }
/** /**
@@ -209,22 +188,16 @@ public class StandardPlugin extends Plugin {
*/ */
private NumberInterface getLogPartialSum(NumberInterface x) { private NumberInterface getLogPartialSum(NumberInterface x) {
if (Thread.currentThread().isInterrupted())
return null;
NumberInterface maxError = getMaxError(x); NumberInterface maxError = getMaxError(x);
x = x.subtract(NaiveNumber.ONE.promoteTo(x.getClass())); //Terms used are for log(x+1). x = x.subtract(NaiveNumber.ONE.promoteTo(x.getClass())); //Terms used are for log(x+1).
NumberInterface currentNumerator = x, currentTerm = x, sum = x; NumberInterface currentNumerator = x, currentTerm = x, sum = x;
int n = 1; int n = 1;
NumberInterface check; while (FUNCTION_ABS.apply(currentTerm).compareTo(maxError) > 0) {
while (!Thread.currentThread().isInterrupted() && (check = FUNCTION_ABS.apply(currentTerm)) != null && check.compareTo(maxError) > 0) {
n++; n++;
if ((currentNumerator = currentNumerator.multiply(x)) == null || (currentNumerator = currentNumerator.negate()) == null) currentNumerator = currentNumerator.multiply(x).negate();
return null;
currentTerm = currentNumerator.divide(new NaiveNumber(n).promoteTo(x.getClass())); currentTerm = currentNumerator.divide(new NaiveNumber(n).promoteTo(x.getClass()));
sum = sum.add(currentTerm); sum = sum.add(currentTerm);
} }
if (Thread.currentThread().isInterrupted())
return null;
return sum; return sum;
} }
@@ -234,27 +207,21 @@ public class StandardPlugin extends Plugin {
* @return the value of log(2) with the appropriate precision. * @return the value of log(2) with the appropriate precision.
*/ */
private NumberInterface getLog2(NumberInterface number) { private NumberInterface getLog2(NumberInterface number) {
if (Thread.currentThread().isInterrupted())
return null;
NumberInterface maxError = getMaxError(number); NumberInterface maxError = getMaxError(number);
//NumberInterface errorBound = (new NaiveNumber(1)).promoteTo(number.getClass()); //NumberInterface errorBound = fromInt(number.getClass(), 1);
//We'll use the series \sigma_{n >= 1) ((1/3^n + 1/4^n) * 1/n) //We'll use the series \sigma_{n >= 1) ((1/3^n + 1/4^n) * 1/n)
//In the following, a=1/3^n, b=1/4^n, c = 1/n. //In the following, a=1/3^n, b=1/4^n, c = 1/n.
//a is also an error bound. //a is also an error bound.
NumberInterface a = (new NaiveNumber(1)).promoteTo(number.getClass()), b = a, c = a; NumberInterface a = fromInt(number.getClass(), 1), b = a, c = a;
NumberInterface sum = NaiveNumber.ZERO.promoteTo(number.getClass()); NumberInterface sum = NaiveNumber.ZERO.promoteTo(number.getClass());
int n = 0; int n = 0;
while (!Thread.currentThread().isInterrupted() && a.compareTo(maxError) >= 1) { while (a.compareTo(maxError) >= 1) {
n++; n++;
a = a.divide((new NaiveNumber(3)).promoteTo(number.getClass())); a = a.divide(fromInt(number.getClass(), 3));
b = b.divide((new NaiveNumber(4)).promoteTo(number.getClass())); b = b.divide(fromInt(number.getClass(), 4));
c = NaiveNumber.ONE.promoteTo(number.getClass()).divide((new NaiveNumber(n)).promoteTo(number.getClass())); c = NaiveNumber.ONE.promoteTo(number.getClass()).divide((new NaiveNumber(n)).promoteTo(number.getClass()));
NumberInterface check; sum = sum.add(a.add(b).multiply(c));
if (a == null || (check = a.add(b)) == null || (check = check.multiply(c)) == null || (sum = sum.add(check)) == null)
return null;
} }
if (Thread.currentThread().isInterrupted())
return null;
return sum; return sum;
} }
}; };
@@ -349,7 +316,7 @@ public class StandardPlugin extends Plugin {
//right and left refer to lhs and rhs in the above inequality. //right and left refer to lhs and rhs in the above inequality.
NumberInterface sum = NaiveNumber.ONE.promoteTo(params[0].getClass()); NumberInterface sum = NaiveNumber.ONE.promoteTo(params[0].getClass());
NumberInterface nextNumerator = params[0]; NumberInterface nextNumerator = params[0];
NumberInterface left = params[0].multiply((new NaiveNumber(3)).promoteTo(params[0].getClass()).intPow(params[0].ceiling().intValue())), right = maxError; NumberInterface left = params[0].multiply(fromInt(params[0].getClass(), 3).intPow(params[0].ceiling().intValue())), right = maxError;
do { do {
sum = sum.add(nextNumerator.divide(factorial(params[0].getClass(), n + 1))); sum = sum.add(nextNumerator.divide(factorial(params[0].getClass(), n + 1)));
n++; n++;
@@ -378,15 +345,11 @@ public class StandardPlugin extends Plugin {
@Override @Override
protected NumberInterface applyInternal(NumberInterface[] params) { protected NumberInterface applyInternal(NumberInterface[] params) {
if (Thread.currentThread().isInterrupted()) return null; if (params[0].compareTo(NaiveNumber.ZERO.promoteTo(params[0].getClass())) == 0)
else if (params[0].compareTo(NaiveNumber.ZERO.promoteTo(params[0].getClass())) == 0)
return NaiveNumber.ZERO.promoteTo(params[0].getClass()); return NaiveNumber.ZERO.promoteTo(params[0].getClass());
else if (params[1].compareTo(NaiveNumber.ZERO.promoteTo(params[0].getClass())) == 0) else if (params[1].compareTo(NaiveNumber.ZERO.promoteTo(params[0].getClass())) == 0)
return NaiveNumber.ONE.promoteTo(params[1].getClass()); return NaiveNumber.ONE.promoteTo(params[1].getClass());
FUNCTION_EXP.apply(FUNCTION_LN.apply(FUNCTION_ABS.apply(params[0])).multiply(params[1])); return FUNCTION_EXP.apply(FUNCTION_LN.apply(FUNCTION_ABS.apply(params[0])).multiply(params[1]));
NumberInterface check = FUNCTION_LN.apply(FUNCTION_ABS.apply(params[0]));
if(check == null) return null;
return FUNCTION_EXP.apply(check.multiply(params[1]));
} }
}); });
/** /**
@@ -401,12 +364,12 @@ public class StandardPlugin extends Plugin {
@Override @Override
protected NumberInterface applyInternal(NumberInterface[] params) { protected NumberInterface applyInternal(NumberInterface[] params) {
NumberInterface pi = getPi(params[0].getClass()); NumberInterface pi = getPi(params[0].getClass());
NumberInterface twoPi = pi.multiply(new NaiveNumber(2).promoteTo(pi.getClass())); NumberInterface twoPi = pi.multiply(fromInt(pi.getClass(), 2));
NumberInterface theta = getSmallAngle(params[0], pi); NumberInterface theta = getSmallAngle(params[0], pi);
//System.out.println(theta); //System.out.println(theta);
if (theta.compareTo(pi.multiply(new NaiveNumber(1.5).promoteTo(twoPi.getClass()))) >= 0) { if (theta.compareTo(pi.multiply(new NaiveNumber(1.5).promoteTo(twoPi.getClass()))) >= 0) {
theta = theta.subtract(twoPi); theta = theta.subtract(twoPi);
} else if (theta.compareTo(pi.divide(new NaiveNumber(2).promoteTo(pi.getClass()))) > 0) { } else if (theta.compareTo(pi.divide(fromInt(pi.getClass(), 2))) > 0) {
theta = pi.subtract(theta); theta = pi.subtract(theta);
} }
//System.out.println(theta); //System.out.println(theta);
@@ -424,7 +387,7 @@ public class StandardPlugin extends Plugin {
@Override @Override
protected NumberInterface applyInternal(NumberInterface[] params) { protected NumberInterface applyInternal(NumberInterface[] params) {
return functionSin.apply(getPi(params[0].getClass()).divide(new NaiveNumber(2).promoteTo(params[0].getClass())) return functionSin.apply(getPi(params[0].getClass()).divide(fromInt(params[0].getClass(), 2))
.subtract(params[0])); .subtract(params[0]));
} }
}; };
@@ -481,7 +444,7 @@ public class StandardPlugin extends Plugin {
@Override @Override
protected NumberInterface applyInternal(NumberInterface[] params) { protected NumberInterface applyInternal(NumberInterface[] params) {
return functionCos.apply(params[0]).divide(functionCos.apply(params[0])); return functionCos.apply(params[0]).divide(functionSin.apply(params[0]));
} }
}; };
@@ -512,7 +475,7 @@ public class StandardPlugin extends Plugin {
* @return the maximum error. * @return the maximum error.
*/ */
private static NumberInterface getMaxError(NumberInterface number) { private static NumberInterface getMaxError(NumberInterface number) {
return (new NaiveNumber(10)).promoteTo(number.getClass()).intPow(-number.getMaxPrecision()); return fromInt(number.getClass(), 10).intPow(-number.getMaxPrecision());
} }
/** /**
@@ -524,8 +487,6 @@ public class StandardPlugin extends Plugin {
* @return a number of numClass with value n factorial. * @return a number of numClass with value n factorial.
*/ */
public static NumberInterface factorial(Class<? extends NumberInterface> numberClass, int n) { public static NumberInterface factorial(Class<? extends NumberInterface> numberClass, int n) {
if (Thread.currentThread().isInterrupted())
return null;
if (!FACTORIAL_LISTS.containsKey(numberClass)) { if (!FACTORIAL_LISTS.containsKey(numberClass)) {
FACTORIAL_LISTS.put(numberClass, new ArrayList<>()); FACTORIAL_LISTS.put(numberClass, new ArrayList<>());
FACTORIAL_LISTS.get(numberClass).add(NaiveNumber.ONE.promoteTo(numberClass)); FACTORIAL_LISTS.get(numberClass).add(NaiveNumber.ONE.promoteTo(numberClass));
@@ -533,12 +494,10 @@ public class StandardPlugin extends Plugin {
} }
ArrayList<NumberInterface> list = FACTORIAL_LISTS.get(numberClass); ArrayList<NumberInterface> list = FACTORIAL_LISTS.get(numberClass);
if (n >= list.size()) { if (n >= list.size()) {
while (!Thread.currentThread().isInterrupted() && list.size() < n + 16) { while (list.size() < n + 16) {
list.add(list.get(list.size() - 1).multiply(new NaiveNumber(list.size()).promoteTo(numberClass))); list.add(list.get(list.size() - 1).multiply(new NaiveNumber(list.size()).promoteTo(numberClass)));
} }
} }
if (Thread.currentThread().isInterrupted())
return null;
return list.get(n); return list.get(n);
} }
@@ -577,26 +536,20 @@ public class StandardPlugin extends Plugin {
return theta; return theta;
} }
public static NumberInterface intPow(NumberInterface number, Class<? extends NumberInterface> numberClass, NumberInterface exponent) { /**
if (Thread.currentThread().isInterrupted()) * Returns a number of class numType with value n.
return null; * @param numType class of number to return.
if (exponent.compareTo((new NaiveNumber(0)).promoteTo(numberClass)) == 0) { * @param n value of returned number.
return (new NaiveNumber(1)).promoteTo(numberClass); * @return numClass instance with value n.
*/
private static NumberInterface fromInt(Class<? extends NumberInterface> numType, int n){
if(!integerValues.containsKey(numType)){
integerValues.put(numType, new HashMap<>());
} }
boolean takeReciprocal = exponent.compareTo((new NaiveNumber(0)).promoteTo(numberClass)) < 0; if(!integerValues.get(numType).containsKey(n)){
exponent = FUNCTION_ABS.apply(exponent); integerValues.get(numType).put(n, new NaiveNumber(n).promoteTo(numType));
NumberInterface power = number;
for (NumberInterface currentExponent = (new NaiveNumber(1)).promoteTo(numberClass); currentExponent.compareTo(exponent) < 0; currentExponent = currentExponent.add((new NaiveNumber(1)).promoteTo(numberClass))) {
power = power.multiply(number);
if (Thread.currentThread().isInterrupted())
return null;
} }
if (takeReciprocal) { return integerValues.get(numType).get(n);
power = (new NaiveNumber(1)).promoteTo(numberClass).divide(power);
}
if (Thread.currentThread().isInterrupted())
return null;
return power;
} }
@Override @Override

View File

@@ -92,15 +92,10 @@ public class BinaryNode extends TreeNode {
@Override @Override
public <T> T reduce(Reducer<T> reducer) { public <T> T reduce(Reducer<T> reducer) {
if (Thread.currentThread().isInterrupted())
return null;
T leftReduce = left.reduce(reducer); T leftReduce = left.reduce(reducer);
T rightReduce = right.reduce(reducer); T rightReduce = right.reduce(reducer);
if (leftReduce == null || rightReduce == null) return null; if (leftReduce == null || rightReduce == null) return null;
T a = reducer.reduceNode(this, leftReduce, rightReduce); return reducer.reduceNode(this, leftReduce, rightReduce);
if (Thread.currentThread().isInterrupted())
return null;
return a;
} }
@Override @Override

View File

@@ -62,17 +62,12 @@ public class FunctionNode extends TreeNode {
@Override @Override
public <T> T reduce(Reducer<T> reducer) { public <T> T reduce(Reducer<T> reducer) {
if (Thread.currentThread().isInterrupted())
return null;
Object[] reducedChildren = new Object[children.size()]; Object[] reducedChildren = new Object[children.size()];
for (int i = 0; i < reducedChildren.length; i++) { for (int i = 0; i < reducedChildren.length; i++) {
reducedChildren[i] = children.get(i).reduce(reducer); reducedChildren[i] = children.get(i).reduce(reducer);
if (Thread.currentThread().isInterrupted() || reducedChildren[i] == null) return null; if (reducedChildren[i] == null) return null;
} }
T a = reducer.reduceNode(this, reducedChildren); return reducer.reduceNode(this, reducedChildren);
if (Thread.currentThread().isInterrupted())
return null;
return a;
} }
@Override @Override

View File

@@ -33,14 +33,9 @@ public class UnaryNode extends TreeNode {
@Override @Override
public <T> T reduce(Reducer<T> reducer) { public <T> T reduce(Reducer<T> reducer) {
if (Thread.currentThread().isInterrupted())
return null;
Object reducedChild = applyTo.reduce(reducer); Object reducedChild = applyTo.reduce(reducer);
if (reducedChild == null) return null; if (reducedChild == null) return null;
T a = reducer.reduceNode(this, reducedChild); return reducer.reduceNode(this, reducedChild);
if (Thread.currentThread().isInterrupted())
return null;
return a;
} }
/** /**

View File

@@ -35,7 +35,7 @@
<Button fx:id="inputButton" text="Calculate" maxWidth="Infinity" <Button fx:id="inputButton" text="Calculate" maxWidth="Infinity"
onAction="#performCalculation"/> onAction="#performCalculation"/>
<Button fx:id="stopButton" text="Stop" maxWidth="Infinity" <Button fx:id="stopButton" text="Stop" maxWidth="Infinity"
onAction="#stopCalculation"/> onAction="#performStop" disable="true"/>
</VBox> </VBox>
</bottom> </bottom>
</BorderPane> </BorderPane>

View File

@@ -0,0 +1,104 @@
package org.nwapw.abacus.tests;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.nwapw.abacus.Abacus;
import org.nwapw.abacus.config.Configuration;
import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.plugin.StandardPlugin;
import org.nwapw.abacus.tree.TreeNode;
public class CalculationTests {
private static Abacus abacus = new Abacus(new Configuration("precise", new String[]{}));
@BeforeClass
public static void prepareTests(){
abacus.getPluginManager().addInstantiated(new StandardPlugin(abacus.getPluginManager()));
abacus.getPluginManager().load();
}
private void testOutput(String input, String parseOutput, String output){
TreeNode parsedTree = abacus.parseString(input);
Assert.assertNotNull(parsedTree);
Assert.assertEquals(parsedTree.toString(), parseOutput);
NumberInterface result = abacus.evaluateTree(parsedTree);
Assert.assertNotNull(result);
Assert.assertTrue(result.toString().startsWith(output));
}
private void testEvalError(String input, String parseOutput){
TreeNode parsedTree = abacus.parseString(input);
Assert.assertNotNull(parsedTree);
Assert.assertEquals(parsedTree.toString(), parseOutput);
Assert.assertNull(abacus.evaluateTree(parsedTree));
}
@Test
public void testAddition(){
testOutput("9.5+10", "(9.5+10)", "19.5");
}
@Test
public void testSubtraction(){
testOutput("9.5-10", "(9.5-10)", "-0.5");
}
@Test
public void testMultiplication(){
testOutput("9.5*10", "(9.5*10)", "95");
}
@Test
public void testDivision(){
testOutput("9.5/2", "(9.5/2)", "4.75");
}
@Test
public void testNegation(){
testOutput("-9.5", "(9.5)`", "-9.5");
}
@Test
public void testFactorial(){
testOutput("7!", "(7)!", "5040");
}
@Test
public void testAbs(){
testOutput("abs(-1)", "abs((1)`)", "1");
testOutput("abs(1)", "abs(1)", "1");
}
@Test
public void testLn(){
testEvalError("ln(-1)", "ln((1)`)");
testOutput("ln2", "ln(2)", "0.6931471805599453094172321214581765680755");
}
@Test
public void testSqrt(){
testOutput("sqrt0", "sqrt(0)", "0");
testOutput("sqrt4", "sqrt(4)", "2");
testOutput("sqrt2", "sqrt(2)", "1.4142135623730950488016887242096980785696");
}
@Test
public void testExp(){
testOutput("exp0", "exp(0)", "1");
testOutput("exp1", "exp(1)", "2.718281828459045235360287471352662497757247");
testOutput("exp300", "exp(300)", "19424263952412559365842088360176992193662086");
testOutput("exp300", "exp(300)", "19424263952412559365842088360176992193662086");
}
@Test
public void testPow(){
testOutput("0^2", "(0^2)", "0");
testOutput("2^0", "(2^0)", "1");
testOutput("2^1", "(2^1)", "2");
testOutput("2^-1", "(2^(1)`)", "0.5");
testOutput("2^50", "(2^50)", "112589990684262");
}
}

View File

@@ -4,6 +4,7 @@ import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.nwapw.abacus.Abacus; import org.nwapw.abacus.Abacus;
import org.nwapw.abacus.config.Configuration;
import org.nwapw.abacus.function.Function; import org.nwapw.abacus.function.Function;
import org.nwapw.abacus.function.Operator; import org.nwapw.abacus.function.Operator;
import org.nwapw.abacus.function.OperatorAssociativity; import org.nwapw.abacus.function.OperatorAssociativity;
@@ -18,7 +19,7 @@ import java.util.List;
public class TokenizerTests { public class TokenizerTests {
private static Abacus abacus = new Abacus(); private static Abacus abacus = new Abacus(new Configuration("precise", new String[]{}));
private static LexerTokenizer lexerTokenizer = new LexerTokenizer(); private static LexerTokenizer lexerTokenizer = new LexerTokenizer();
private static Function subtractFunction = new Function() { private static Function subtractFunction = new Function() {
@Override @Override