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 c1d8862..c2ec80a 100755 --- a/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java @@ -6,8 +6,6 @@ import org.nwapw.abacus.number.NaiveNumber; import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.PreciseNumber; import org.nwapw.abacus.plugin.standard.*; -import org.nwapw.abacus.tree.TreeNode; -import org.nwapw.abacus.tree.VariableNode; import java.util.ArrayList; import java.util.HashMap; @@ -21,36 +19,11 @@ public class StandardPlugin extends Plugin { /** * The set operator. */ - public final TreeValueOperator opSet = new TreeValueOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { - @Override - public boolean matchesParams(MutableEvaluationContext context, TreeNode[] params) { - return params.length == 2 && params[0] instanceof VariableNode; - } - - @Override - public NumberInterface applyInternal(MutableEvaluationContext context, TreeNode[] params) { - String assignTo = ((VariableNode) params[0]).getVariable(); - NumberInterface value = params[1].reduce(context.getInheritedReducer()); - context.setVariable(assignTo, value); - return value; - } - }; + public static final TreeValueOperator OP_SET = new OperatorSet(); /** * The define operator. */ - public final TreeValueOperator opDefine = new TreeValueOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { - @Override - public boolean matchesParams(MutableEvaluationContext context, TreeNode[] params) { - return params.length == 2 && params[0] instanceof VariableNode; - } - - @Override - public NumberInterface applyInternal(MutableEvaluationContext context, TreeNode[] params) { - String assignTo = ((VariableNode) params[0]).getVariable(); - context.setDefinition(assignTo, params[1]); - return params[1].reduce(context.getInheritedReducer()); - } - }; + public final TreeValueOperator OP_DEFINE = new OperatorDefine(); /** * The addition operator, + */ @@ -129,49 +102,11 @@ public class StandardPlugin extends Plugin { /** * The permutation operator. */ - public static final NumberOperator OP_NPR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { - @Override - public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { - return params.length == 2 && params[0].fractionalPart().signum() == 0 - && params[1].fractionalPart().signum() == 0; - } - - @Override - public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { - NumberImplementation implementation = context.getInheritedNumberImplementation(); - if (params[0].compareTo(params[1]) < 0 || - params[0].signum() < 0 || - (params[0].signum() == 0 && params[1].signum() != 0)) return implementation.instanceForString("0"); - NumberInterface total = implementation.instanceForString("1"); - NumberInterface multiplyBy = params[0]; - NumberInterface remainingMultiplications = params[1]; - NumberInterface halfway = params[0].divide(implementation.instanceForString("2")); - if (remainingMultiplications.compareTo(halfway) > 0) { - remainingMultiplications = params[0].subtract(remainingMultiplications); - } - while (remainingMultiplications.signum() > 0) { - total = total.multiply(multiplyBy); - remainingMultiplications = remainingMultiplications.subtract(implementation.instanceForString("1")); - multiplyBy = multiplyBy.subtract(implementation.instanceForString("1")); - } - return total; - } - }; + public static final NumberOperator OP_NPR = new OperatorNpr(); /** * The combination operator. */ - public static final NumberOperator OP_NCR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { - @Override - public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { - return params.length == 2 && params[0].fractionalPart().signum() == 0 - && params[1].fractionalPart().signum() == 0; - } - - @Override - public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { - return OP_NPR.apply(context, params).divide(OP_FACTORIAL.apply(context, params[1])); - } - }; + public static final NumberOperator OP_NCR = new OperatorNcr(); /** * The absolute value function, abs(-3) = 3 */ @@ -284,34 +219,7 @@ 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(MutableEvaluationContext context, NumberInterface[] params) { - NumberInterface zero = context.getInheritedNumberImplementation().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(MutableEvaluationContext context, NumberInterface[] params) { - NumberImplementation implementation = context.getInheritedNumberImplementation(); - 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(context, params[1]).compareTo(implementation.instanceForString(Integer.toString(Integer.MAX_VALUE))) < 0 - && FUNCTION_ABS.apply(context, params[1]).compareTo(implementation.instanceForString("1")) >= 0) { - NumberInterface[] newParams = {params[0], params[1].fractionalPart()}; - return params[0].intPow(params[1].floor().intValue()).multiply(applyInternal(context, newParams)); - } - return FUNCTION_EXP.apply(context, FUNCTION_LN.apply(context, FUNCTION_ABS.apply(context, params[0])).multiply(params[1])); - } - }; + public static final NumberOperator OP_CARET = new OperatorCaret(); /** * The square root function. */ @@ -677,8 +585,8 @@ public class StandardPlugin extends Plugin { registerOperator("^", OP_CARET); registerOperator("!", OP_FACTORIAL); - registerTreeValueOperator("=", opSet); - registerTreeValueOperator(":=", opDefine); + registerTreeValueOperator("=", OP_SET); + registerTreeValueOperator(":=", OP_DEFINE); registerOperator("nPr", OP_NPR); registerOperator("nCr", OP_NCR); diff --git a/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorCaret.kt b/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorCaret.kt new file mode 100644 index 0000000..db81267 --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorCaret.kt @@ -0,0 +1,38 @@ +package org.nwapw.abacus.plugin.standard + +import org.nwapw.abacus.context.MutableEvaluationContext +import org.nwapw.abacus.function.NumberOperator +import org.nwapw.abacus.function.OperatorAssociativity +import org.nwapw.abacus.function.OperatorType +import org.nwapw.abacus.number.NumberInterface +import org.nwapw.abacus.plugin.StandardPlugin.* + +/** + * The power operator. + * + * This is a standard operator that brings one number to the power of the other. + */ +class OperatorCaret: NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2) { + + override fun matchesParams(context: MutableEvaluationContext, params: Array) = + params.size == 2 + && !(params[0].signum() == 0 && params[1].signum() == 0) + && !(params[0].signum() == -1 && params[1].fractionalPart().signum() != 0) + + override fun applyInternal(context: MutableEvaluationContext, params: Array): NumberInterface { + val implementation = context.inheritedNumberImplementation + if (params[0].signum() == 0) + return implementation.instanceForString("0") + else if (params[1].signum() == 0) + return implementation.instanceForString("1") + //Detect integer bases: + if (params[0].fractionalPart().signum() == 0 + && FUNCTION_ABS.apply(context, params[1]) < implementation.instanceForString(Integer.toString(Integer.MAX_VALUE)) + && FUNCTION_ABS.apply(context, params[1]) >= implementation.instanceForString("1")) { + val newParams = arrayOf(params[0], params[1].fractionalPart()) + return params[0].intPow(params[1].floor().intValue()) * applyInternal(context, newParams) + } + return FUNCTION_EXP.apply(context, FUNCTION_LN.apply(context, FUNCTION_ABS.apply(context, params[0])) * params[1]) + } + +} \ No newline at end of file diff --git a/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorDefine.kt b/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorDefine.kt new file mode 100644 index 0000000..6cb4979 --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorDefine.kt @@ -0,0 +1,28 @@ +package org.nwapw.abacus.plugin.standard + +import org.nwapw.abacus.context.MutableEvaluationContext +import org.nwapw.abacus.function.OperatorAssociativity +import org.nwapw.abacus.function.OperatorType +import org.nwapw.abacus.function.TreeValueOperator +import org.nwapw.abacus.number.NumberInterface +import org.nwapw.abacus.tree.TreeNode +import org.nwapw.abacus.tree.VariableNode + +/** + * The definition operator. + * + * This is a standard operator that creates a definition - something that doesn't capture variable values + * when it's created, but rather the variables themselves, and changes when the variables it uses change. + */ +class OperatorDefine: TreeValueOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { + + override fun matchesParams(context: MutableEvaluationContext, params: Array) = + params.size == 2 && params[0] is VariableNode + + override fun applyInternal(context: MutableEvaluationContext, params: Array): NumberInterface { + val assignTo = (params[0] as VariableNode).variable + context.setDefinition(assignTo, params[1]) + return params[1].reduce(context.inheritedReducer) + } + +} \ No newline at end of file diff --git a/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorFactorial.kt b/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorFactorial.kt index 4f5eab3..5af7970 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorFactorial.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorFactorial.kt @@ -6,11 +6,16 @@ import org.nwapw.abacus.function.OperatorAssociativity import org.nwapw.abacus.function.OperatorType import org.nwapw.abacus.number.NumberInterface +/** + * The factorial operator. + * + * This is a standard operator that simply evaluates the factorial of a number. + */ class OperatorFactorial: NumberOperator(OperatorAssociativity.LEFT, OperatorType.UNARY_POSTFIX, 0) { override fun matchesParams(context: MutableEvaluationContext, params: Array) = params.size == 1 - && params[0].fractionalPart().compareTo(context.inheritedNumberImplementation.instanceForString("0")) == 0 + && params[0].fractionalPart().signum() == 0 && params[0].signum() >= 0 override fun applyInternal(context: MutableEvaluationContext, params: Array): NumberInterface { diff --git a/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorNcr.kt b/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorNcr.kt new file mode 100644 index 0000000..ae897d0 --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorNcr.kt @@ -0,0 +1,25 @@ +package org.nwapw.abacus.plugin.standard + +import org.nwapw.abacus.context.MutableEvaluationContext +import org.nwapw.abacus.function.NumberOperator +import org.nwapw.abacus.function.OperatorAssociativity +import org.nwapw.abacus.function.OperatorType +import org.nwapw.abacus.number.NumberInterface +import org.nwapw.abacus.plugin.StandardPlugin.* + +/** + * The "N choose R" operator. + * + * This is a standard operator that returns the number of possible combinations, regardless of order, + * of a certain size can be taken out of a pool of a bigger size. + */ +class OperatorNcr: NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { + + override fun matchesParams(context: MutableEvaluationContext, params: Array) = + params.size == 2 && params[0].fractionalPart().signum() == 0 + && params[1].fractionalPart().signum() == 0 + + override fun applyInternal(context: MutableEvaluationContext, params: Array) = + OP_NPR.apply(context, *params) / OP_FACTORIAL.apply(context, params[1]) + +} \ No newline at end of file diff --git a/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorNegate.kt b/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorNegate.kt index 35b40a8..df085c2 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorNegate.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorNegate.kt @@ -6,6 +6,11 @@ import org.nwapw.abacus.function.OperatorAssociativity import org.nwapw.abacus.function.OperatorType import org.nwapw.abacus.number.NumberInterface +/** + * The negation operator. + * + * This is a standard operator that negates a number. + */ class OperatorNegate: NumberOperator(OperatorAssociativity.LEFT, OperatorType.UNARY_PREFIX, 0) { override fun matchesParams(context: MutableEvaluationContext, params: Array) = diff --git a/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorNpr.kt b/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorNpr.kt new file mode 100644 index 0000000..21e61d3 --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorNpr.kt @@ -0,0 +1,42 @@ +package org.nwapw.abacus.plugin.standard + +import org.nwapw.abacus.context.MutableEvaluationContext +import org.nwapw.abacus.function.NumberOperator +import org.nwapw.abacus.function.OperatorAssociativity +import org.nwapw.abacus.function.OperatorType +import org.nwapw.abacus.number.NumberInterface + +/** + * The "N pick R" operator. + * + * his is a standard operator that returns the number of possible combinations + * of a certain size can be taken out of a pool of a bigger size. + */ +class OperatorNpr: NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { + + override fun matchesParams(context: MutableEvaluationContext, params: Array) = + params.size == 2 && params[0].fractionalPart().signum() == 0 + && params[1].fractionalPart().signum() == 0 + + override fun applyInternal(context: MutableEvaluationContext, params: Array): NumberInterface { + val implementation = context.inheritedNumberImplementation + if (params[0] < params[1] || + params[0].signum() < 0 || + params[0].signum() == 0 && params[1].signum() != 0) + return implementation.instanceForString("0") + var total = implementation.instanceForString("1") + var multiplyBy = params[0] + var remainingMultiplications = params[1] + val halfway = params[0] / implementation.instanceForString("2") + if (remainingMultiplications > halfway) { + remainingMultiplications = params[0] - remainingMultiplications + } + while (remainingMultiplications.signum() > 0) { + total *= multiplyBy + remainingMultiplications -= implementation.instanceForString("1") + multiplyBy -= implementation.instanceForString("1") + } + return total + } + +} \ No newline at end of file diff --git a/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorSet.kt b/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorSet.kt new file mode 100644 index 0000000..23e9b1f --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/plugin/standard/OperatorSet.kt @@ -0,0 +1,28 @@ +package org.nwapw.abacus.plugin.standard + +import org.nwapw.abacus.context.MutableEvaluationContext +import org.nwapw.abacus.function.OperatorAssociativity +import org.nwapw.abacus.function.OperatorType +import org.nwapw.abacus.function.TreeValueOperator +import org.nwapw.abacus.number.NumberInterface +import org.nwapw.abacus.tree.TreeNode +import org.nwapw.abacus.tree.VariableNode + +/** + * The set operator. + * + * This is a standard operator that assigns a value to a variable name. + */ +class OperatorSet: TreeValueOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { + + override fun matchesParams(context: MutableEvaluationContext, params: Array) = + params.size == 2 && params[0] is VariableNode + + override fun applyInternal(context: MutableEvaluationContext, params: Array): NumberInterface { + val assignTo = (params[0] as VariableNode).variable + val value = params[1].reduce(context.inheritedReducer) + context.setVariable(assignTo, value) + return value + } + +} \ No newline at end of file