1
0
mirror of https://github.com/DanilaFe/abacus synced 2024-12-22 15:30:09 -08:00

Require applicable interfaces to be passed an implementation they use.

This commit is contained in:
Danila Fedorin 2017-09-01 17:45:32 -07:00
parent f7c07ca04d
commit 2b700d3911
9 changed files with 173 additions and 135 deletions

View File

@ -138,16 +138,14 @@ public class Abacus {
} }
/** /**
* Creates a number from a string. * Gets the number implementation.
* * @return the number implementation to use for creating numbers.
* @param numberString the string to create the number from.
* @return the resulting number.
*/ */
public NumberInterface numberFromString(String numberString) { public NumberImplementation getNumberImplementation(){
NumberImplementation toInstantiate = NumberImplementation selectedImplementation =
pluginManager.numberImplementationFor(configuration.getNumberImplementation()); pluginManager.numberImplementationFor(configuration.getNumberImplementation());
if (toInstantiate == null) toInstantiate = DEFAULT_IMPLEMENTATION; if(selectedImplementation != null) return selectedImplementation;
return DEFAULT_IMPLEMENTATION;
}
return toInstantiate.instanceForString(numberString);
}
} }

View File

@ -20,12 +20,13 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_ADD = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { public static final NumberOperator OP_ADD = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 2; return params.length == 2;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return params[0].add(params[1]); return params[0].add(params[1]);
} }
}; };
@ -34,12 +35,13 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_SUBTRACT = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { public static final NumberOperator OP_SUBTRACT = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 2; return params.length == 2;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return params[0].subtract(params[1]); return params[0].subtract(params[1]);
} }
@ -49,12 +51,13 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_NEGATE = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.UNARY_PREFIX, 0) { public static final NumberOperator OP_NEGATE = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.UNARY_PREFIX, 0) {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return params[0].negate(); return params[0].negate();
} }
}; };
@ -63,12 +66,13 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_MULTIPLY = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) { public static final NumberOperator OP_MULTIPLY = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 2; return params.length == 2;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return params[0].multiply(params[1]); return params[0].multiply(params[1]);
} }
}; };
@ -91,13 +95,14 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_SQRT = new NumberFunction() { public static final NumberFunction FUNCTION_SQRT = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return OP_CARET.apply(params[0], ((new NaiveNumber(0.5)).promoteTo(params[0].getClass()))); return OP_CARET.apply(implementation, params[0], ((new NaiveNumber(0.5)).promoteTo(params[0].getClass())));
} }
}; };
/** /**
@ -111,7 +116,7 @@ public class StandardPlugin extends Plugin {
@Override @Override
public NumberInterface instanceForPi() { public NumberInterface instanceForPi() {
NumberInterface C = FUNCTION_SQRT.apply(new PreciseNumber("10005")).multiply(new PreciseNumber("426880")); NumberInterface C = FUNCTION_SQRT.apply(this, new PreciseNumber("10005")).multiply(new PreciseNumber("426880"));
NumberInterface M = PreciseNumber.ONE; NumberInterface M = PreciseNumber.ONE;
NumberInterface L = new PreciseNumber("13591409"); NumberInterface L = new PreciseNumber("13591409");
NumberInterface X = M; NumberInterface X = M;
@ -145,12 +150,13 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_DIVIDE = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) { public static final NumberOperator OP_DIVIDE = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 2 && params[1].compareTo(fromInt(params[0].getClass(), 0)) != 0; return params.length == 2 && params[1].compareTo(fromInt(params[0].getClass(), 0)) != 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return params[0].divide(params[1]); return params[0].divide(params[1]);
} }
}; };
@ -160,14 +166,15 @@ public class StandardPlugin extends Plugin {
public static final NumberOperator OP_FACTORIAL = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.UNARY_POSTFIX, 0) { public static final NumberOperator OP_FACTORIAL = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.UNARY_POSTFIX, 0) {
//private HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>> storedList = new HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>>(); //private HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>> storedList = new HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>>();
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1 return params.length == 1
&& params[0].fractionalPart().compareTo(fromInt(params[0].getClass(), 0)) == 0 && params[0].fractionalPart().compareTo(fromInt(params[0].getClass(), 0)) == 0
&& params[0].signum() >= 0; && params[0].signum() >= 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
if (params[0].signum() == 0) { if (params[0].signum() == 0) {
return fromInt(params[0].getClass(), 1); return fromInt(params[0].getClass(), 1);
} }
@ -191,13 +198,14 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_NPR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { public static final NumberOperator OP_NPR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 2 && params[0].fractionalPart().signum() == 0 return params.length == 2 && params[0].fractionalPart().signum() == 0
&& params[1].fractionalPart().signum() == 0; && params[1].fractionalPart().signum() == 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
if (params[0].compareTo(params[1]) < 0 || if (params[0].compareTo(params[1]) < 0 ||
params[0].signum() < 0 || params[0].signum() < 0 ||
(params[0].signum() == 0 && params[1].signum() != 0)) return fromInt(params[0].getClass(), 0); (params[0].signum() == 0 && params[1].signum() != 0)) return fromInt(params[0].getClass(), 0);
@ -221,14 +229,15 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_NCR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { public static final NumberOperator OP_NCR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 2 && params[0].fractionalPart().signum() == 0 return params.length == 2 && params[0].fractionalPart().signum() == 0
&& params[1].fractionalPart().signum() == 0; && params[1].fractionalPart().signum() == 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return OP_NPR.apply(params).divide(OP_FACTORIAL.apply(params[1])); return OP_NPR.apply(implementation, params).divide(OP_FACTORIAL.apply(implementation, params[1]));
} }
}; };
/** /**
@ -236,12 +245,13 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_ABS = new NumberFunction() { public static final NumberFunction FUNCTION_ABS = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return params[0].multiply(fromInt(params[0].getClass(), params[0].signum())); return params[0].multiply(fromInt(params[0].getClass(), params[0].signum()));
} }
}; };
@ -250,16 +260,17 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_LN = new NumberFunction() { public static final NumberFunction FUNCTION_LN = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1 && params[0].compareTo(fromInt(params[0].getClass(), 0)) > 0; return params.length == 1 && params[0].compareTo(fromInt(params[0].getClass(), 0)) > 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
NumberInterface param = params[0]; NumberInterface param = params[0];
NumberInterface one = fromInt(param.getClass(), 1); NumberInterface one = fromInt(param.getClass(), 1);
int powersOf2 = 0; int powersOf2 = 0;
while (FUNCTION_ABS.apply(param.subtract(one)).compareTo(new NaiveNumber(0.1).promoteTo(param.getClass())) >= 0) { while (FUNCTION_ABS.apply(implementation, param.subtract(one)).compareTo(new NaiveNumber(0.1).promoteTo(param.getClass())) >= 0) {
if (param.subtract(one).signum() == 1) { if (param.subtract(one).signum() == 1) {
param = param.divide(fromInt(param.getClass(), 2)); param = param.divide(fromInt(param.getClass(), 2));
powersOf2++; powersOf2++;
@ -276,7 +287,7 @@ public class StandardPlugin extends Plugin {
} }
} }
} }
return getLog2(param).multiply(fromInt(param.getClass(), powersOf2)).add(getLogPartialSum(param)); return getLog2(implementation, param).multiply(fromInt(param.getClass(), powersOf2)).add(getLogPartialSum(implementation, param));
} }
/** /**
@ -285,13 +296,13 @@ public class StandardPlugin extends Plugin {
* @param x value at which the series is evaluated. 0 < x < 2. (x=2 is convergent but impractical.) * @param x value at which the series is evaluated. 0 < x < 2. (x=2 is convergent but impractical.)
* @return the partial sum. * @return the partial sum.
*/ */
private NumberInterface getLogPartialSum(NumberInterface x) { private NumberInterface getLogPartialSum(NumberImplementation implementation, NumberInterface x) {
NumberInterface maxError = x.getMaxError(); NumberInterface maxError = x.getMaxError();
x = x.subtract(fromInt(x.getClass(), 1)); //Terms used are for log(x+1). x = x.subtract(fromInt(x.getClass(), 1)); //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;
while (FUNCTION_ABS.apply(currentTerm).compareTo(maxError) > 0) { while (FUNCTION_ABS.apply(implementation, currentTerm).compareTo(maxError) > 0) {
n++; n++;
currentNumerator = currentNumerator.multiply(x).negate(); currentNumerator = currentNumerator.multiply(x).negate();
currentTerm = currentNumerator.divide(fromInt(x.getClass(), n)); currentTerm = currentNumerator.divide(fromInt(x.getClass(), n));
@ -305,7 +316,7 @@ public class StandardPlugin extends Plugin {
* @param number a number of the same type as the return type. (Used for precision.) * @param number a number of the same type as the return type. (Used for precision.)
* @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(NumberImplementation implementation, NumberInterface number) {
NumberInterface maxError = number.getMaxError(); NumberInterface maxError = number.getMaxError();
//NumberInterface errorBound = fromInt(number.getClass(), 1); //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)
@ -330,12 +341,13 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_RAND_INT = new NumberFunction() { public static final NumberFunction FUNCTION_RAND_INT = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return fromInt(params[0].getClass(), (int) Math.round(Math.random() * params[0].floor().intValue())); return fromInt(params[0].getClass(), (int) Math.round(Math.random() * params[0].floor().intValue()));
} }
}; };
@ -345,17 +357,18 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_EXP = new NumberFunction() { public static final NumberFunction FUNCTION_EXP = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
NumberInterface maxError = params[0].getMaxError(); NumberInterface maxError = params[0].getMaxError();
int n = 0; int n = 0;
if (params[0].signum() < 0) { if (params[0].signum() < 0) {
NumberInterface[] negatedParams = {params[0].negate()}; NumberInterface[] negatedParams = {params[0].negate()};
return fromInt(params[0].getClass(), 1).divide(applyInternal(negatedParams)); return fromInt(params[0].getClass(), 1).divide(applyInternal(implementation, negatedParams));
} else { } else {
//We need n such that x^(n+1) * 3^ceil(x) <= maxError * (n+1)!. //We need n such that x^(n+1) * 3^ceil(x) <= maxError * (n+1)!.
//right and left refer to lhs and rhs in the above inequality. //right and left refer to lhs and rhs in the above inequality.
@ -382,7 +395,7 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_CARET = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2) { public static final NumberOperator OP_CARET = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2) {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
NumberInterface zero = fromInt(params[0].getClass(), 0); NumberInterface zero = fromInt(params[0].getClass(), 0);
return params.length == 2 return params.length == 2
&& !(params[0].compareTo(zero) == 0 && !(params[0].compareTo(zero) == 0
@ -390,8 +403,9 @@ public class StandardPlugin extends Plugin {
&& !(params[0].signum() == -1 && params[1].fractionalPart().compareTo(zero) != 0); && !(params[0].signum() == -1 && params[1].fractionalPart().compareTo(zero) != 0);
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
NumberInterface zero = fromInt(params[0].getClass(), 0); NumberInterface zero = fromInt(params[0].getClass(), 0);
if (params[0].compareTo(zero) == 0) if (params[0].compareTo(zero) == 0)
return zero; return zero;
@ -399,12 +413,12 @@ public class StandardPlugin extends Plugin {
return fromInt(params[0].getClass(), 1); return fromInt(params[0].getClass(), 1);
//Detect integer bases: //Detect integer bases:
if (params[0].fractionalPart().compareTo(fromInt(params[0].getClass(), 0)) == 0 if (params[0].fractionalPart().compareTo(fromInt(params[0].getClass(), 0)) == 0
&& FUNCTION_ABS.apply(params[1]).compareTo(fromInt(params[0].getClass(), Integer.MAX_VALUE)) < 0 && FUNCTION_ABS.apply(implementation, params[1]).compareTo(fromInt(params[0].getClass(), Integer.MAX_VALUE)) < 0
&& FUNCTION_ABS.apply(params[1]).compareTo(fromInt(params[1].getClass(), 1)) >= 0) { && FUNCTION_ABS.apply(implementation, params[1]).compareTo(fromInt(params[1].getClass(), 1)) >= 0) {
NumberInterface[] newParams = {params[0], params[1].fractionalPart()}; NumberInterface[] newParams = {params[0], params[1].fractionalPart()};
return params[0].intPow(params[1].floor().intValue()).multiply(applyInternal(newParams)); return params[0].intPow(params[1].floor().intValue()).multiply(applyInternal(implementation, newParams));
} }
return FUNCTION_EXP.apply(FUNCTION_LN.apply(FUNCTION_ABS.apply(params[0])).multiply(params[1])); return FUNCTION_EXP.apply(implementation, FUNCTION_LN.apply(implementation, FUNCTION_ABS.apply(implementation, params[0])).multiply(params[1]));
} }
}; };
/** /**
@ -412,15 +426,16 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionSin = new NumberFunction() { public final NumberFunction functionSin = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
NumberInterface pi = piFor(params[0].getClass()); NumberInterface pi = piFor(params[0].getClass());
NumberInterface twoPi = pi.multiply(fromInt(pi.getClass(), 2)); NumberInterface twoPi = pi.multiply(fromInt(pi.getClass(), 2));
NumberInterface theta = getSmallAngle(params[0], pi); NumberInterface theta = getSmallAngle(implementation, 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);
@ -428,7 +443,7 @@ public class StandardPlugin extends Plugin {
theta = pi.subtract(theta); theta = pi.subtract(theta);
} }
//System.out.println(theta); //System.out.println(theta);
return sinTaylor(theta); return sinTaylor(implementation, theta);
} }
}; };
/** /**
@ -436,13 +451,14 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionCos = new NumberFunction() { public final NumberFunction functionCos = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return functionSin.apply(piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2)) return functionSin.apply(implementation, piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2))
.subtract(params[0])); .subtract(params[0]));
} }
}; };
@ -451,13 +467,14 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionTan = new NumberFunction() { public final NumberFunction functionTan = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return functionSin.apply(params[0]).divide(functionCos.apply(params[0])); return functionSin.apply(implementation, params[0]).divide(functionCos.apply(implementation, params[0]));
} }
}; };
/** /**
@ -465,13 +482,14 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionSec = new NumberFunction() { public final NumberFunction functionSec = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return fromInt(params[0].getClass(), 1).divide(functionCos.apply(params[0])); return fromInt(params[0].getClass(), 1).divide(functionCos.apply(implementation, params[0]));
} }
}; };
/** /**
@ -479,13 +497,14 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionCsc = new NumberFunction() { public final NumberFunction functionCsc = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return fromInt(params[0].getClass(), 1).divide(functionSin.apply(params[0])); return fromInt(params[0].getClass(), 1).divide(functionSin.apply(implementation, params[0]));
} }
}; };
/** /**
@ -493,13 +512,14 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionCot = new NumberFunction() { public final NumberFunction functionCot = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return functionCos.apply(params[0]).divide(functionSin.apply(params[0])); return functionCos.apply(implementation, params[0]).divide(functionSin.apply(implementation, params[0]));
} }
}; };
@ -508,23 +528,24 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArcsin = new NumberFunction() { public final NumberFunction functionArcsin = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1 return params.length == 1
&& FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) <= 0; && FUNCTION_ABS.apply(implementation, params[0]).compareTo(fromInt(params[0].getClass(), 1)) <= 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
if (FUNCTION_ABS.apply(params[0]).compareTo(new NaiveNumber(0.8).promoteTo(params[0].getClass())) >= 0) { if (FUNCTION_ABS.apply(implementation, params[0]).compareTo(new NaiveNumber(0.8).promoteTo(params[0].getClass())) >= 0) {
NumberInterface[] newParams = {FUNCTION_SQRT.apply(fromInt(params[0].getClass(), 1).subtract(params[0].multiply(params[0])))}; NumberInterface[] newParams = {FUNCTION_SQRT.apply(implementation, fromInt(params[0].getClass(), 1).subtract(params[0].multiply(params[0])))};
return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2)) return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2))
.subtract(applyInternal(newParams)).multiply(fromInt(params[0].getClass(), params[0].signum())); .subtract(applyInternal(implementation, newParams)).multiply(fromInt(params[0].getClass(), params[0].signum()));
} }
NumberInterface currentTerm = params[0], sum = currentTerm, NumberInterface currentTerm = params[0], sum = currentTerm,
multiplier = currentTerm.multiply(currentTerm), summandBound = sum.getMaxError().multiply(fromInt(sum.getClass(), 1).subtract(multiplier)), multiplier = currentTerm.multiply(currentTerm), summandBound = sum.getMaxError().multiply(fromInt(sum.getClass(), 1).subtract(multiplier)),
power = currentTerm, coefficient = fromInt(params[0].getClass(), 1); power = currentTerm, coefficient = fromInt(params[0].getClass(), 1);
int exponent = 1; int exponent = 1;
while (FUNCTION_ABS.apply(currentTerm).compareTo(summandBound) > 0) { while (FUNCTION_ABS.apply(implementation, currentTerm).compareTo(summandBound) > 0) {
exponent += 2; exponent += 2;
power = power.multiply(multiplier); power = power.multiply(multiplier);
coefficient = coefficient.multiply(fromInt(params[0].getClass(), exponent - 2)) coefficient = coefficient.multiply(fromInt(params[0].getClass(), exponent - 2))
@ -541,14 +562,15 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArccos = new NumberFunction() { public final NumberFunction functionArccos = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1 && FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) <= 0; return params.length == 1 && FUNCTION_ABS.apply(implementation, params[0]).compareTo(fromInt(params[0].getClass(), 1)) <= 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2)) return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2))
.subtract(functionArcsin.apply(params)); .subtract(functionArcsin.apply(implementation, params));
} }
}; };
@ -557,14 +579,15 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArccsc = new NumberFunction() { public final NumberFunction functionArccsc = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1 && FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) >= 0; return params.length == 1 && FUNCTION_ABS.apply(implementation, params[0]).compareTo(fromInt(params[0].getClass(), 1)) >= 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
NumberInterface[] reciprocalParamArr = {fromInt(params[0].getClass(), 1).divide(params[0])}; NumberInterface[] reciprocalParamArr = {fromInt(params[0].getClass(), 1).divide(params[0])};
return functionArcsin.apply(reciprocalParamArr); return functionArcsin.apply(implementation, reciprocalParamArr);
} }
}; };
@ -573,14 +596,15 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArcsec = new NumberFunction() { public final NumberFunction functionArcsec = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1 && FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) >= 0; return params.length == 1 && FUNCTION_ABS.apply(implementation, params[0]).compareTo(fromInt(params[0].getClass(), 1)) >= 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
NumberInterface[] reciprocalParamArr = {fromInt(params[0].getClass(), 1).divide(params[0])}; NumberInterface[] reciprocalParamArr = {fromInt(params[0].getClass(), 1).divide(params[0])};
return functionArccos.apply(reciprocalParamArr); return functionArccos.apply(implementation, reciprocalParamArr);
} }
}; };
@ -589,20 +613,21 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArctan = new NumberFunction() { public final NumberFunction functionArctan = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
if (params[0].signum() == -1) { if (params[0].signum() == -1) {
NumberInterface[] negatedParams = {params[0].negate()}; NumberInterface[] negatedParams = {params[0].negate()};
return applyInternal(negatedParams).negate(); return applyInternal(implementation, negatedParams).negate();
} }
if (params[0].compareTo(fromInt(params[0].getClass(), 1)) > 0) { if (params[0].compareTo(fromInt(params[0].getClass(), 1)) > 0) {
NumberInterface[] reciprocalParams = {fromInt(params[0].getClass(), 1).divide(params[0])}; NumberInterface[] reciprocalParams = {fromInt(params[0].getClass(), 1).divide(params[0])};
return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2)) return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2))
.subtract(applyInternal(reciprocalParams)); .subtract(applyInternal(implementation, reciprocalParams));
} }
if (params[0].compareTo(fromInt(params[0].getClass(), 1)) == 0) { if (params[0].compareTo(fromInt(params[0].getClass(), 1)) == 0) {
return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 4)); return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 4));
@ -610,12 +635,12 @@ public class StandardPlugin extends Plugin {
if (params[0].compareTo(new NaiveNumber(0.9).promoteTo(params[0].getClass())) >= 0) { if (params[0].compareTo(new NaiveNumber(0.9).promoteTo(params[0].getClass())) >= 0) {
NumberInterface[] newParams = {params[0].multiply(fromInt(params[0].getClass(), 2)) NumberInterface[] newParams = {params[0].multiply(fromInt(params[0].getClass(), 2))
.divide(fromInt(params[0].getClass(), 1).subtract(params[0].multiply(params[0])))}; .divide(fromInt(params[0].getClass(), 1).subtract(params[0].multiply(params[0])))};
return applyInternal(newParams).divide(fromInt(params[0].getClass(), 2)); return applyInternal(implementation, newParams).divide(fromInt(params[0].getClass(), 2));
} }
NumberInterface currentPower = params[0], currentTerm = currentPower, sum = currentTerm, NumberInterface currentPower = params[0], currentTerm = currentPower, sum = currentTerm,
maxError = params[0].getMaxError(), multiplier = currentPower.multiply(currentPower).negate(); maxError = params[0].getMaxError(), multiplier = currentPower.multiply(currentPower).negate();
int n = 1; int n = 1;
while (FUNCTION_ABS.apply(currentTerm).compareTo(maxError) > 0) { while (FUNCTION_ABS.apply(implementation, currentTerm).compareTo(maxError) > 0) {
n += 2; n += 2;
currentPower = currentPower.multiply(multiplier); currentPower = currentPower.multiply(multiplier);
currentTerm = currentPower.divide(fromInt(currentPower.getClass(), n)); currentTerm = currentPower.divide(fromInt(currentPower.getClass(), n));
@ -630,14 +655,14 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArccot = new NumberFunction() { public final NumberFunction functionArccot = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2)) return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2))
.subtract(functionArctan.apply(params)); .subtract(functionArctan.apply(implementation, params));
} }
}; };
@ -690,7 +715,7 @@ public class StandardPlugin extends Plugin {
* @param x where the series is evaluated. * @param x where the series is evaluated.
* @return the value of the series * @return the value of the series
*/ */
private static NumberInterface sinTaylor(NumberInterface x) { private static NumberInterface sinTaylor(NumberImplementation implementation, NumberInterface x) {
NumberInterface power = x, multiplier = x.multiply(x).negate(), currentTerm = x, sum = x; NumberInterface power = x, multiplier = x.multiply(x).negate(), currentTerm = x, sum = x;
NumberInterface maxError = x.getMaxError(); NumberInterface maxError = x.getMaxError();
int n = 1; int n = 1;
@ -699,7 +724,7 @@ public class StandardPlugin extends Plugin {
power = power.multiply(multiplier); power = power.multiply(multiplier);
currentTerm = power.divide(factorial(x.getClass(), n)); currentTerm = power.divide(factorial(x.getClass(), n));
sum = sum.add(currentTerm); sum = sum.add(currentTerm);
} while (FUNCTION_ABS.apply(currentTerm).compareTo(maxError) > 0); } while (FUNCTION_ABS.apply(implementation, currentTerm).compareTo(maxError) > 0);
return sum; return sum;
} }
@ -709,10 +734,10 @@ public class StandardPlugin extends Plugin {
* @param phi an angle (in radians). * @param phi an angle (in radians).
* @return theta in [0, 2pi) that differs from phi by a multiple of 2pi. * @return theta in [0, 2pi) that differs from phi by a multiple of 2pi.
*/ */
private static NumberInterface getSmallAngle(NumberInterface phi, NumberInterface pi) { private static NumberInterface getSmallAngle(NumberImplementation implementation, NumberInterface phi, NumberInterface pi) {
NumberInterface twoPi = pi.multiply(fromInt(pi.getClass(), 2)); NumberInterface twoPi = pi.multiply(fromInt(pi.getClass(), 2));
NumberInterface theta = FUNCTION_ABS.apply(phi).subtract(twoPi NumberInterface theta = FUNCTION_ABS.apply(implementation, phi).subtract(twoPi
.multiply(FUNCTION_ABS.apply(phi).divide(twoPi).floor())); //Now theta is in [0, 2pi). .multiply(FUNCTION_ABS.apply(implementation, phi).divide(twoPi).floor())); //Now theta is in [0, 2pi).
if (phi.signum() < 0) { if (phi.signum() < 0) {
theta = twoPi.subtract(theta); theta = twoPi.subtract(theta);
} }

View File

@ -3,6 +3,8 @@ package org.nwapw.abacus.tree;
import org.nwapw.abacus.Abacus; import org.nwapw.abacus.Abacus;
import org.nwapw.abacus.function.*; import org.nwapw.abacus.function.*;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.number.PromotionManager;
import org.nwapw.abacus.number.PromotionResult;
/** /**
* A reducer implementation that turns a tree into a single number. * A reducer implementation that turns a tree into a single number.
@ -26,19 +28,22 @@ public class NumberReducer implements Reducer<NumberInterface> {
@Override @Override
public NumberInterface reduceNode(TreeNode node, Object... children) { public NumberInterface reduceNode(TreeNode node, Object... children) {
PromotionManager manager = abacus.getPromotionManager();
if (node instanceof NumberNode) { if (node instanceof NumberNode) {
return abacus.numberFromString(((NumberNode) node).getNumber()); return abacus.getNumberImplementation().instanceForString(((NumberNode) node).getNumber());
} else if(node instanceof VariableNode) { } else if(node instanceof VariableNode) {
return abacus.numberFromString("0"); return abacus.getNumberImplementation().instanceForString("0");
} else if (node instanceof NumberBinaryNode) { } else if (node instanceof NumberBinaryNode) {
NumberInterface left = (NumberInterface) children[0]; NumberInterface left = (NumberInterface) children[0];
NumberInterface right = (NumberInterface) children[1]; NumberInterface right = (NumberInterface) children[1];
NumberOperator operator = abacus.getPluginManager().operatorFor(((BinaryNode) node).getOperation()); NumberOperator operator = abacus.getPluginManager().operatorFor(((BinaryNode) node).getOperation());
return operator.apply(left, right); PromotionResult result = manager.promote(left, right);
if(result == null) return null;
return operator.apply(result.getPromotedTo(), result.getItems());
} else if (node instanceof NumberUnaryNode) { } else if (node instanceof NumberUnaryNode) {
NumberInterface child = (NumberInterface) children[0]; NumberInterface child = (NumberInterface) children[0];
NumberOperator operator = abacus.getPluginManager().operatorFor(((UnaryNode) node).getOperation()); NumberOperator operator = abacus.getPluginManager().operatorFor(((UnaryNode) node).getOperation());
return operator.apply(child); return operator.apply(abacus.getPluginManager().interfaceImplementationFor(child.getClass()), child);
} else if (node instanceof FunctionNode) { } else if (node instanceof FunctionNode) {
NumberInterface[] convertedChildren = new NumberInterface[children.length]; NumberInterface[] convertedChildren = new NumberInterface[children.length];
for (int i = 0; i < convertedChildren.length; i++) { for (int i = 0; i < convertedChildren.length; i++) {
@ -46,7 +51,9 @@ public class NumberReducer implements Reducer<NumberInterface> {
} }
NumberFunction function = abacus.getPluginManager().functionFor(((FunctionNode) node).getCallTo()); NumberFunction function = abacus.getPluginManager().functionFor(((FunctionNode) node).getCallTo());
if (function == null) return null; if (function == null) return null;
return function.apply(convertedChildren); PromotionResult result = manager.promote(convertedChildren);
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; CallNode callNode = (CallNode) node;
TreeNode[] realChildren = new TreeNode[callNode.getChildren().size()]; TreeNode[] realChildren = new TreeNode[callNode.getChildren().size()];
@ -56,19 +63,19 @@ public class NumberReducer implements Reducer<NumberInterface> {
TreeValueFunction function = TreeValueFunction function =
abacus.getPluginManager().treeValueFunctionFor(callNode.getCallTo()); abacus.getPluginManager().treeValueFunctionFor(callNode.getCallTo());
if(function == null) return null; if(function == null) return null;
return function.applyWithReducer(this, realChildren); return function.applyWithReducer(abacus.getNumberImplementation(), this, realChildren);
} else if (node instanceof TreeValueBinaryNode) { } else if (node instanceof TreeValueBinaryNode) {
BinaryNode binaryNode = (BinaryNode) node; BinaryNode binaryNode = (BinaryNode) node;
TreeValueOperator operator = abacus.getPluginManager() TreeValueOperator operator = abacus.getPluginManager()
.treeValueOperatorFor(binaryNode.getOperation()); .treeValueOperatorFor(binaryNode.getOperation());
if(operator == null) return null; if(operator == null) return null;
return operator.applyWithReducer(this, binaryNode.getLeft(), binaryNode.getRight()); return operator.applyWithReducer(abacus.getNumberImplementation(), this, binaryNode.getLeft(), binaryNode.getRight());
} else if(node instanceof TreeValueUnaryNode) { } else if(node instanceof TreeValueUnaryNode) {
UnaryNode unaryNode = (UnaryNode) node; UnaryNode unaryNode = (UnaryNode) node;
TreeValueOperator operator = abacus.getPluginManager() TreeValueOperator operator = abacus.getPluginManager()
.treeValueOperatorFor(unaryNode.getOperation()); .treeValueOperatorFor(unaryNode.getOperation());
if(operator == null) return null; if(operator == null) return null;
return operator.applyWithReducer(this, unaryNode.getApplyTo()); return operator.applyWithReducer(abacus.getNumberImplementation(), this, unaryNode.getApplyTo());
} }
return null; return null;
} }

View File

@ -1,5 +1,7 @@
package org.nwapw.abacus.function.applicable package org.nwapw.abacus.function.applicable
import org.nwapw.abacus.plugin.NumberImplementation
/** /**
* A class that can be applied to arguments. * A class that can be applied to arguments.
* *
@ -15,7 +17,7 @@ interface Applicable<in T : Any, out O : Any> {
* @param params the parameter array to verify for compatibility. * @param params the parameter array to verify for compatibility.
* @return whether the array can be used with applyInternal. * @return whether the array can be used with applyInternal.
*/ */
fun matchesParams(params: Array<out T>): Boolean fun matchesParams(implementation: NumberImplementation, params: Array<out T>): Boolean
/** /**
* Applies the applicable object to the given parameters, * Applies the applicable object to the given parameters,
@ -23,7 +25,7 @@ interface Applicable<in T : Any, out O : Any> {
* @param params the parameters to apply to. * @param params the parameters to apply to.
* @return the result of the application. * @return the result of the application.
*/ */
fun applyInternal(params: Array<out T>): O? fun applyInternal(implementation: NumberImplementation, params: Array<out T>): O?
/** /**
* If the parameters can be used with this applicable, returns * If the parameters can be used with this applicable, returns
@ -32,9 +34,9 @@ interface Applicable<in T : Any, out O : Any> {
* @param params the parameters to apply to. * @param params the parameters to apply to.
* @return the result of the operation, or null if parameters do not match. * @return the result of the operation, or null if parameters do not match.
*/ */
fun apply(vararg params: T): O? { fun apply(implementation: NumberImplementation, vararg params: T): O? {
if (!matchesParams(params)) return null if (!matchesParams(implementation, params)) return null
return applyInternal(params) return applyInternal(implementation, params)
} }
} }

View File

@ -1,5 +1,6 @@
package org.nwapw.abacus.function.applicable package org.nwapw.abacus.function.applicable
import org.nwapw.abacus.plugin.NumberImplementation
import org.nwapw.abacus.tree.Reducer import org.nwapw.abacus.tree.Reducer
/** /**
@ -18,7 +19,7 @@ interface ReducerApplicable<in T : Any, out O : Any, in R : Any> {
* given parameters. * given parameters.
* @param params the parameters to check. * @param params the parameters to check.
*/ */
fun matchesParams(params: Array<out T>): Boolean fun matchesParams(implementation: NumberImplementation, params: Array<out T>): Boolean
/** /**
* Applies this applicable to the given arguments, and reducer. * Applies this applicable to the given arguments, and reducer.
@ -26,7 +27,7 @@ interface ReducerApplicable<in T : Any, out O : Any, in R : Any> {
* @param params the arguments to apply to. * @param params the arguments to apply to.
* @return the result of the application. * @return the result of the application.
*/ */
fun applyWithReducerInternal(reducer: Reducer<R>, params: Array<out T>): O? fun applyWithReducerInternal(implementation: NumberImplementation, reducer: Reducer<R>, params: Array<out T>): O?
/** /**
* Applies this applicable to the given arguments, and reducer, * Applies this applicable to the given arguments, and reducer,
@ -35,9 +36,9 @@ interface ReducerApplicable<in T : Any, out O : Any, in R : Any> {
* @param params the arguments to apply to. * @param params the arguments to apply to.
* @return the result of the application, or null if the arguments are incompatible. * @return the result of the application, or null if the arguments are incompatible.
*/ */
fun applyWithReducer(reducer: Reducer<R>, vararg params: T): O? { fun applyWithReducer(implementation: NumberImplementation, reducer: Reducer<R>, vararg params: T): O? {
if (!matchesParams(params)) return null if (!matchesParams(implementation, params)) return null
return applyWithReducerInternal(reducer, params) return applyWithReducerInternal(implementation, reducer, params)
} }
} }

View File

@ -25,15 +25,15 @@ class PromotionManager(val abacus: Abacus) {
}) })
} }
fun promote(vararg numbers: NumberInterface): Array<NumberInterface>? { fun promote(vararg numbers: NumberInterface): PromotionResult? {
val pluginManager = abacus.pluginManager val pluginManager = abacus.pluginManager
val implementations = numbers.map { pluginManager.interfaceImplementationFor(it.javaClass) } val implementations = numbers.map { pluginManager.interfaceImplementationFor(it.javaClass) }
val highestPriority = implementations.sortedBy { it.priority }.last() val highestPriority = implementations.sortedBy { it.priority }.last()
return numbers.map { return PromotionResult(items = numbers.map {
if(it.javaClass == highestPriority.implementation) it if(it.javaClass == highestPriority.implementation) it
else getPathBetween(pluginManager.interfaceImplementationFor(it.javaClass), highestPriority) else getPathBetween(pluginManager.interfaceImplementationFor(it.javaClass), highestPriority)
?.promote(it) ?: return null ?.promote(it) ?: return null
}.toTypedArray() }.toTypedArray(), promotedTo = highestPriority)
} }
} }

View File

@ -0,0 +1,5 @@
package org.nwapw.abacus.number
import org.nwapw.abacus.plugin.NumberImplementation
data class PromotionResult(val promotedTo: NumberImplementation, val items: Array<NumberInterface>)

View File

@ -9,6 +9,7 @@ import org.nwapw.abacus.function.*;
import org.nwapw.abacus.lexing.pattern.Match; import org.nwapw.abacus.lexing.pattern.Match;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.parsing.LexerTokenizer; import org.nwapw.abacus.parsing.LexerTokenizer;
import org.nwapw.abacus.plugin.NumberImplementation;
import org.nwapw.abacus.plugin.Plugin; import org.nwapw.abacus.plugin.Plugin;
import org.nwapw.abacus.tree.TokenType; import org.nwapw.abacus.tree.TokenType;
@ -20,12 +21,12 @@ public class TokenizerTests {
private static LexerTokenizer lexerTokenizer = new LexerTokenizer(); private static LexerTokenizer lexerTokenizer = new LexerTokenizer();
private static NumberFunction subtractFunction = new NumberFunction() { private static NumberFunction subtractFunction = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return params.length == 2; return params.length == 2;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return params[0].subtract(params[1]); return params[0].subtract(params[1]);
} }
}; };
@ -36,26 +37,26 @@ public class TokenizerTests {
0) { 0) {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return true; return true;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return subtractFunction.apply(params); return subtractFunction.apply(implementation, params);
} }
}); });
registerOperator("-", new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, registerOperator("-", new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX,
0) { 0) {
@Override @Override
public boolean matchesParams(NumberInterface[] params) { public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) {
return true; return true;
} }
@Override @Override
public NumberInterface applyInternal(NumberInterface[] params) { public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) {
return subtractFunction.apply(params); return subtractFunction.apply(implementation, params);
} }
}); });
registerFunction("subtract", subtractFunction); registerFunction("subtract", subtractFunction);

View File

@ -14,8 +14,7 @@ import org.nwapw.abacus.Abacus;
import org.nwapw.abacus.config.Configuration; import org.nwapw.abacus.config.Configuration;
import org.nwapw.abacus.function.Documentation; import org.nwapw.abacus.function.Documentation;
import org.nwapw.abacus.function.DocumentationType; import org.nwapw.abacus.function.DocumentationType;
import org.nwapw.abacus.number.ComputationInterruptedException; import org.nwapw.abacus.number.*;
import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.plugin.ClassFinder; 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;