diff --git a/core/src/main/java/org/nwapw/abacus/Abacus.java b/core/src/main/java/org/nwapw/abacus/Abacus.java index 22c82f4..c9ecf87 100644 --- a/core/src/main/java/org/nwapw/abacus/Abacus.java +++ b/core/src/main/java/org/nwapw/abacus/Abacus.java @@ -1,9 +1,7 @@ package org.nwapw.abacus; import org.nwapw.abacus.config.Configuration; -import org.nwapw.abacus.number.NaiveNumber; import org.nwapw.abacus.number.NumberInterface; -import org.nwapw.abacus.number.PreciseNumber; import org.nwapw.abacus.number.PromotionManager; import org.nwapw.abacus.parsing.LexerTokenizer; import org.nwapw.abacus.parsing.ShuntingYardParser; @@ -14,8 +12,6 @@ import org.nwapw.abacus.plugin.StandardPlugin; import org.nwapw.abacus.tree.NumberReducer; import org.nwapw.abacus.tree.TreeNode; -import java.math.BigDecimal; - /** * The main calculator class. This is responsible * for piecing together all of the components, allowing @@ -72,6 +68,7 @@ public class Abacus { /** * Gets the promotion manager. + * * @return the promotion manager. */ public PromotionManager getPromotionManager() { @@ -139,12 +136,13 @@ public class Abacus { /** * Gets the number implementation. + * * @return the number implementation to use for creating numbers. */ - public NumberImplementation getNumberImplementation(){ + public NumberImplementation getNumberImplementation() { NumberImplementation selectedImplementation = pluginManager.numberImplementationFor(configuration.getNumberImplementation()); - if(selectedImplementation != null) return selectedImplementation; + if (selectedImplementation != null) return selectedImplementation; return DEFAULT_IMPLEMENTATION; } diff --git a/core/src/main/java/org/nwapw/abacus/parsing/LexerTokenizer.java b/core/src/main/java/org/nwapw/abacus/parsing/LexerTokenizer.java index 2d7b16b..be57744 100644 --- a/core/src/main/java/org/nwapw/abacus/parsing/LexerTokenizer.java +++ b/core/src/main/java/org/nwapw/abacus/parsing/LexerTokenizer.java @@ -50,13 +50,13 @@ public class LexerTokenizer implements Tokenizer>, PluginListen for (String operator : manager.getAllOperators()) { lexer.register(Pattern.sanitize(operator), TokenType.OP); } - for (String operator : manager.getAllTreeValueOperators()){ + for (String operator : manager.getAllTreeValueOperators()) { lexer.register(Pattern.sanitize(operator), TokenType.TREE_VALUE_OP); } for (String function : manager.getAllFunctions()) { lexer.register(Pattern.sanitize(function), TokenType.FUNCTION); } - for (String function : manager.getAllTreeValueFunctions()){ + for (String function : manager.getAllTreeValueFunctions()) { lexer.register(Pattern.sanitize(function), TokenType.TREE_VALUE_FUNCTION); } } @@ -66,13 +66,13 @@ public class LexerTokenizer implements Tokenizer>, PluginListen for (String operator : manager.getAllOperators()) { lexer.unregister(Pattern.sanitize(operator), TokenType.OP); } - for (String operator : manager.getAllTreeValueOperators()){ + for (String operator : manager.getAllTreeValueOperators()) { lexer.unregister(Pattern.sanitize(operator), TokenType.TREE_VALUE_OP); } for (String function : manager.getAllFunctions()) { lexer.unregister(Pattern.sanitize(function), TokenType.FUNCTION); } - for (String function : manager.getAllTreeValueFunctions()){ + for (String function : manager.getAllTreeValueFunctions()) { lexer.unregister(Pattern.sanitize(function), TokenType.TREE_VALUE_FUNCTION); } } diff --git a/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java b/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java index 7490d96..9d326a8 100644 --- a/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java +++ b/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java @@ -134,7 +134,7 @@ public class ShuntingYardParser implements Parser>, PluginListe TreeNode right = constructRecursive(matches); TreeNode left = constructRecursive(matches); if (left == null || right == null) return null; - if(matchType == TokenType.OP) { + if (matchType == TokenType.OP) { return new NumberBinaryNode(operator, left, right); } else { return new TreeValueBinaryNode(operator, left, right); @@ -142,7 +142,7 @@ public class ShuntingYardParser implements Parser>, PluginListe } else { TreeNode applyTo = constructRecursive(matches); if (applyTo == null) return null; - if(matchType == TokenType.OP){ + if (matchType == TokenType.OP) { return new NumberUnaryNode(operator, applyTo); } else { return new TreeValueUnaryNode(operator, applyTo); @@ -155,7 +155,7 @@ public class ShuntingYardParser implements Parser>, PluginListe } else if (matchType == TokenType.FUNCTION || matchType == TokenType.TREE_VALUE_FUNCTION) { String functionName = match.getContent(); CallNode node; - if(matchType == TokenType.FUNCTION){ + if (matchType == TokenType.FUNCTION) { node = new FunctionNode(functionName); } else { node = new TreeValueFunctionNode(functionName); diff --git a/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java b/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java index 73908a4..6dafcda 100644 --- a/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java @@ -241,7 +241,7 @@ public class PluginManager { * @param name the class for which to find the implementation name. * @return the implementation name. */ - public String interfaceImplementationNameFor(Class name){ + public String interfaceImplementationNameFor(Class name) { return interfaceImplementationNames.get(name); } diff --git a/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java b/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java index 873c45f..c149d4a 100755 --- a/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java @@ -7,7 +7,6 @@ import org.nwapw.abacus.number.PreciseNumber; import java.util.ArrayList; import java.util.HashMap; -import java.util.function.BiFunction; /** * The plugin providing standard functions such as addition and subtraction to @@ -24,7 +23,7 @@ public class StandardPlugin extends Plugin { return params.length == 2; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { return params[0].add(params[1]); @@ -39,7 +38,7 @@ public class StandardPlugin extends Plugin { return params.length == 2; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { return params[0].subtract(params[1]); @@ -55,7 +54,7 @@ public class StandardPlugin extends Plugin { return params.length == 1; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { return params[0].negate(); @@ -70,7 +69,7 @@ public class StandardPlugin extends Plugin { return params.length == 2; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { return params[0].multiply(params[1]); @@ -90,21 +89,6 @@ public class StandardPlugin extends Plugin { return new NaiveNumber(Math.PI); } }; - /** - * The square root function. - */ - public static final NumberFunction FUNCTION_SQRT = new NumberFunction() { - @Override - public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { - return params.length == 1; - } - - - @Override - public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { - return OP_CARET.apply(implementation, params[0], implementation.instanceForString(".5")); - } - }; /** * The implementation for the infinite-precision BigDecimal. */ @@ -147,10 +131,10 @@ public class StandardPlugin extends Plugin { public static final NumberOperator OP_DIVIDE = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) { @Override public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { - return params.length == 2 && params[1].compareTo(implementation.instanceForString(Integer.toString( 0))) != 0; + return params.length == 2 && params[1].compareTo(implementation.instanceForString(Integer.toString(0))) != 0; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { return params[0].divide(params[1]); @@ -168,7 +152,7 @@ public class StandardPlugin extends Plugin { && params[0].signum() >= 0; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { if (params[0].signum() == 0) { @@ -199,7 +183,7 @@ public class StandardPlugin extends Plugin { && params[1].fractionalPart().signum() == 0; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { if (params[0].compareTo(params[1]) < 0 || @@ -230,7 +214,7 @@ public class StandardPlugin extends Plugin { && params[1].fractionalPart().signum() == 0; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { return OP_NPR.apply(implementation, params).divide(OP_FACTORIAL.apply(implementation, params[1])); @@ -245,7 +229,7 @@ public class StandardPlugin extends Plugin { return params.length == 1; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { return params[0].multiply(implementation.instanceForString(Integer.toString(params[0].signum()))); @@ -260,7 +244,7 @@ public class StandardPlugin extends Plugin { return params.length == 1 && params[0].compareTo(implementation.instanceForString("0")) > 0; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { NumberInterface param = params[0]; @@ -341,12 +325,58 @@ public class StandardPlugin extends Plugin { return params.length == 1; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { return implementation.instanceForString(Long.toString(Math.round(Math.random() * params[0].floor().intValue()))); } }; + /** + * The caret / pow operator, ^ + */ + public static final NumberOperator OP_CARET = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2) { + @Override + public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { + NumberInterface zero = implementation.instanceForString("0"); + return params.length == 2 + && !(params[0].compareTo(zero) == 0 + && params[1].compareTo(zero) == 0) + && !(params[0].signum() == -1 && params[1].fractionalPart().compareTo(zero) != 0); + } + + + @Override + public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { + NumberInterface zero = implementation.instanceForString("0"); + if (params[0].compareTo(zero) == 0) + return zero; + else if (params[1].compareTo(zero) == 0) + return implementation.instanceForString("1"); + //Detect integer bases: + if (params[0].fractionalPart().compareTo(implementation.instanceForString("0")) == 0 + && FUNCTION_ABS.apply(implementation, params[1]).compareTo(implementation.instanceForString(Integer.toString(Integer.MAX_VALUE))) < 0 + && FUNCTION_ABS.apply(implementation, params[1]).compareTo(implementation.instanceForString("1")) >= 0) { + NumberInterface[] newParams = {params[0], params[1].fractionalPart()}; + return params[0].intPow(params[1].floor().intValue()).multiply(applyInternal(implementation, newParams)); + } + return FUNCTION_EXP.apply(implementation, FUNCTION_LN.apply(implementation, FUNCTION_ABS.apply(implementation, params[0])).multiply(params[1])); + } + }; + /** + * The square root function. + */ + public static final NumberFunction FUNCTION_SQRT = new NumberFunction() { + @Override + public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { + return params.length == 1; + } + + + @Override + public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { + return OP_CARET.apply(implementation, params[0], implementation.instanceForString(".5")); + } + }; private static final HashMap> FACTORIAL_LISTS = new HashMap<>(); /** * The exponential function, exp(1) = e^1 = 2.71... @@ -357,7 +387,7 @@ public class StandardPlugin extends Plugin { return params.length == 1; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { NumberInterface maxError = params[0].getMaxError(); @@ -386,37 +416,6 @@ public class StandardPlugin extends Plugin { } } }; - /** - * The caret / pow operator, ^ - */ - public static final NumberOperator OP_CARET = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2) { - @Override - public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { - NumberInterface zero = implementation.instanceForString("0"); - return params.length == 2 - && !(params[0].compareTo(zero) == 0 - && params[1].compareTo(zero) == 0) - && !(params[0].signum() == -1 && params[1].fractionalPart().compareTo(zero) != 0); - } - - - @Override - public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { - NumberInterface zero = implementation.instanceForString("0"); - if (params[0].compareTo(zero) == 0) - return zero; - else if (params[1].compareTo(zero) == 0) - return implementation.instanceForString("1"); - //Detect integer bases: - if (params[0].fractionalPart().compareTo(implementation.instanceForString("0")) == 0 - && FUNCTION_ABS.apply(implementation, params[1]).compareTo(implementation.instanceForString(Integer.toString(Integer.MAX_VALUE))) < 0 - && FUNCTION_ABS.apply(implementation, params[1]).compareTo(implementation.instanceForString("1")) >= 0) { - NumberInterface[] newParams = {params[0], params[1].fractionalPart()}; - return params[0].intPow(params[1].floor().intValue()).multiply(applyInternal(implementation, newParams)); - } - return FUNCTION_EXP.apply(implementation, FUNCTION_LN.apply(implementation, FUNCTION_ABS.apply(implementation, params[0])).multiply(params[1])); - } - }; /** * The sine function (the argument is interpreted in radians). */ @@ -426,7 +425,7 @@ public class StandardPlugin extends Plugin { return params.length == 1; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { NumberInterface pi = piFor(params[0].getClass()); @@ -451,7 +450,7 @@ public class StandardPlugin extends Plugin { return params.length == 1; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { return functionSin.apply(implementation, piFor(params[0].getClass()).divide(implementation.instanceForString("2")) @@ -467,7 +466,7 @@ public class StandardPlugin extends Plugin { return params.length == 1; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { return functionSin.apply(implementation, params[0]).divide(functionCos.apply(implementation, params[0])); @@ -482,7 +481,7 @@ public class StandardPlugin extends Plugin { return params.length == 1; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { return implementation.instanceForString("1").divide(functionCos.apply(implementation, params[0])); @@ -497,7 +496,7 @@ public class StandardPlugin extends Plugin { return params.length == 1; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { return implementation.instanceForString("1").divide(functionSin.apply(implementation, params[0])); @@ -512,7 +511,7 @@ public class StandardPlugin extends Plugin { return params.length == 1; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { return functionCos.apply(implementation, params[0]).divide(functionSin.apply(implementation, params[0])); @@ -529,7 +528,7 @@ public class StandardPlugin extends Plugin { && FUNCTION_ABS.apply(implementation, params[0]).compareTo(implementation.instanceForString("1")) <= 0; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { if (FUNCTION_ABS.apply(implementation, params[0]).compareTo(implementation.instanceForString(".8")) >= 0) { @@ -544,9 +543,9 @@ public class StandardPlugin extends Plugin { while (FUNCTION_ABS.apply(implementation, currentTerm).compareTo(summandBound) > 0) { exponent += 2; power = power.multiply(multiplier); - coefficient = coefficient.multiply(implementation.instanceForString(Integer.toString( exponent - 2))) - .divide(implementation.instanceForString(Integer.toString( exponent - 1))); - currentTerm = power.multiply(coefficient).divide(implementation.instanceForString(Integer.toString( exponent))); + coefficient = coefficient.multiply(implementation.instanceForString(Integer.toString(exponent - 2))) + .divide(implementation.instanceForString(Integer.toString(exponent - 1))); + currentTerm = power.multiply(coefficient).divide(implementation.instanceForString(Integer.toString(exponent))); sum = sum.add(currentTerm); } return sum; @@ -562,7 +561,7 @@ public class StandardPlugin extends Plugin { return params.length == 1 && FUNCTION_ABS.apply(implementation, params[0]).compareTo(implementation.instanceForString("1")) <= 0; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { return piFor(params[0].getClass()).divide(implementation.instanceForString("2")) @@ -579,7 +578,7 @@ public class StandardPlugin extends Plugin { return params.length == 1 && FUNCTION_ABS.apply(implementation, params[0]).compareTo(implementation.instanceForString("1")) >= 0; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { NumberInterface[] reciprocalParamArr = {implementation.instanceForString("1").divide(params[0])}; @@ -596,7 +595,7 @@ public class StandardPlugin extends Plugin { return params.length == 1 && FUNCTION_ABS.apply(implementation, params[0]).compareTo(implementation.instanceForString("1")) >= 0; } - + @Override public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { NumberInterface[] reciprocalParamArr = {implementation.instanceForString("1").divide(params[0])}; @@ -639,7 +638,7 @@ public class StandardPlugin extends Plugin { while (FUNCTION_ABS.apply(implementation, currentTerm).compareTo(maxError) > 0) { n += 2; currentPower = currentPower.multiply(multiplier); - currentTerm = currentPower.divide(implementation.instanceForString(Integer.toString( n))); + currentTerm = currentPower.divide(implementation.instanceForString(Integer.toString(n))); sum = sum.add(currentTerm); } return sum; @@ -671,7 +670,7 @@ public class StandardPlugin extends Plugin { * computes factorials of non-negative integers. * * @param implementation type of number to return. - * @param n non-negative integer. + * @param n non-negative integer. * @return a number of numClass with value n factorial. */ public static NumberInterface factorial(NumberImplementation implementation, int n) { @@ -684,7 +683,7 @@ public class StandardPlugin extends Plugin { ArrayList list = FACTORIAL_LISTS.get(implementation); if (n >= list.size()) { while (list.size() < n + 16) { - list.add(list.get(list.size() - 1).multiply(implementation.instanceForString(Integer.toString( list.size())))); + list.add(list.get(list.size() - 1).multiply(implementation.instanceForString(Integer.toString(list.size())))); } } return list.get(n); diff --git a/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java b/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java index 8d8dbbc..5d497ec 100644 --- a/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java +++ b/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java @@ -1,7 +1,10 @@ package org.nwapw.abacus.tree; import org.nwapw.abacus.Abacus; -import org.nwapw.abacus.function.*; +import org.nwapw.abacus.function.NumberFunction; +import org.nwapw.abacus.function.NumberOperator; +import org.nwapw.abacus.function.TreeValueFunction; +import org.nwapw.abacus.function.TreeValueOperator; import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.PromotionManager; import org.nwapw.abacus.number.PromotionResult; @@ -31,14 +34,14 @@ public class NumberReducer implements Reducer { PromotionManager manager = abacus.getPromotionManager(); if (node instanceof NumberNode) { return abacus.getNumberImplementation().instanceForString(((NumberNode) node).getNumber()); - } else if(node instanceof VariableNode) { + } else if (node instanceof VariableNode) { return abacus.getNumberImplementation().instanceForString("0"); } else if (node instanceof NumberBinaryNode) { NumberInterface left = (NumberInterface) children[0]; NumberInterface right = (NumberInterface) children[1]; NumberOperator operator = abacus.getPluginManager().operatorFor(((BinaryNode) node).getOperation()); PromotionResult result = manager.promote(left, right); - if(result == null) return null; + if (result == null) return null; return operator.apply(result.getPromotedTo(), result.getItems()); } else if (node instanceof NumberUnaryNode) { NumberInterface child = (NumberInterface) children[0]; @@ -52,29 +55,29 @@ public class NumberReducer implements Reducer { NumberFunction function = abacus.getPluginManager().functionFor(((FunctionNode) node).getCallTo()); if (function == null) return null; PromotionResult result = manager.promote(convertedChildren); - if(result == null) return null; + if (result == null) return null; return function.apply(result.getPromotedTo(), result.getItems()); - } else if (node instanceof TreeValueFunctionNode){ + } else if (node instanceof TreeValueFunctionNode) { CallNode callNode = (CallNode) node; TreeNode[] realChildren = new TreeNode[callNode.getChildren().size()]; - for(int i = 0; i < realChildren.length; i++){ + for (int i = 0; i < realChildren.length; i++) { realChildren[i] = callNode.getChildren().get(i); } TreeValueFunction function = abacus.getPluginManager().treeValueFunctionFor(callNode.getCallTo()); - if(function == null) return null; + if (function == null) return null; return function.applyWithReducer(abacus.getNumberImplementation(), this, realChildren); } else if (node instanceof TreeValueBinaryNode) { BinaryNode binaryNode = (BinaryNode) node; TreeValueOperator operator = abacus.getPluginManager() .treeValueOperatorFor(binaryNode.getOperation()); - if(operator == null) return null; + if (operator == null) return null; return operator.applyWithReducer(abacus.getNumberImplementation(), this, binaryNode.getLeft(), binaryNode.getRight()); - } else if(node instanceof TreeValueUnaryNode) { + } else if (node instanceof TreeValueUnaryNode) { UnaryNode unaryNode = (UnaryNode) node; TreeValueOperator operator = abacus.getPluginManager() .treeValueOperatorFor(unaryNode.getOperation()); - if(operator == null) return null; + if (operator == null) return null; return operator.applyWithReducer(abacus.getNumberImplementation(), this, unaryNode.getApplyTo()); } return null;