mirror of
				https://github.com/DanilaFe/abacus
				synced 2025-11-03 18:33:41 -08:00 
			
		
		
		
	Move all functions to a static context, stopping unnecessary lookups.
This commit is contained in:
		
							parent
							
								
									6b8d8497e2
								
							
						
					
					
						commit
						03eb669eb3
					
				@ -16,6 +16,213 @@ import java.util.function.BiFunction;
 | 
			
		||||
 */
 | 
			
		||||
public class StandardPlugin extends Plugin {
 | 
			
		||||
 | 
			
		||||
    public static final Operator OP_ADD = new Operator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0, new Function() {
 | 
			
		||||
        @Override
 | 
			
		||||
        protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
            return params.length >= 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
            NumberInterface sum = params[0];
 | 
			
		||||
            for(int i = 1; i < params.length; i++){
 | 
			
		||||
                sum = sum.add(params[i]);
 | 
			
		||||
            }
 | 
			
		||||
            return sum;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    public static final Operator OP_SUBTRACT = new Operator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0, new Function() {
 | 
			
		||||
        @Override
 | 
			
		||||
        protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
            return params.length == 2;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
            return params[0].subtract(params[1]);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    public static final Operator OP_MULTIPLY = new Operator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX,1, new Function() {
 | 
			
		||||
        @Override
 | 
			
		||||
        protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
            return params.length >= 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
            NumberInterface product = params[0];
 | 
			
		||||
            for(int i = 1; i < params.length; i++){
 | 
			
		||||
                product = product.multiply(params[i]);
 | 
			
		||||
            }
 | 
			
		||||
            return product;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    public static final Operator OP_DIVIDE = new Operator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX,1, new Function() {
 | 
			
		||||
        @Override
 | 
			
		||||
        protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
            return params.length >= 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
            NumberInterface product = params[0];
 | 
			
		||||
            for(int i = 1; i < params.length; i++){
 | 
			
		||||
                product = product.multiply(params[i]);
 | 
			
		||||
            }
 | 
			
		||||
            return product;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    public static final Operator OP_CARET = new Operator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2, new Function() {
 | 
			
		||||
        @Override
 | 
			
		||||
        protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
            return params.length == 2;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
            return FUNCTION_EXP.apply(FUNCTION_LN.apply(params[0]).multiply(params[1]));
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    public static final Operator OP_FACTORIAL = new Operator(OperatorAssociativity.RIGHT, OperatorType.UNARY_POSTFIX, 0, new Function() {
 | 
			
		||||
        //private HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>> storedList = new HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>>();
 | 
			
		||||
        @Override
 | 
			
		||||
        protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
            return params.length == 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
            if(params[0].signum() == 0){
 | 
			
		||||
                return (new NaiveNumber(1)).promoteTo(params[0].getClass());
 | 
			
		||||
            }
 | 
			
		||||
            NumberInterface factorial = params[0];
 | 
			
		||||
            NumberInterface multiplier = params[0];
 | 
			
		||||
            //It is necessary to later prevent calls of factorial on anything but non-negative integers.
 | 
			
		||||
            while((multiplier = multiplier.subtract(NaiveNumber.ONE.promoteTo(multiplier.getClass()))).signum() == 1){
 | 
			
		||||
                factorial = factorial.multiply(multiplier);
 | 
			
		||||
            }
 | 
			
		||||
            return factorial;
 | 
			
		||||
                /*if(!storedList.containsKey(params[0].getClass())){
 | 
			
		||||
                    storedList.put(params[0].getClass(), new ArrayList<NumberInterface>());
 | 
			
		||||
                    storedList.get(params[0].getClass()).add(NaiveNumber.ONE.promoteTo(params[0].getClass()));
 | 
			
		||||
                    storedList.get(params[0].getClass()).add(NaiveNumber.ONE.promoteTo(params[0].getClass()));
 | 
			
		||||
                }*/
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    public static final Function FUNCTION_ABS = new Function() {
 | 
			
		||||
        @Override
 | 
			
		||||
        protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
            return params.length == 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
            return params[0].multiply((new NaiveNumber(params[0].signum())).promoteTo(params[0].getClass()));
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    public static final Function FUNCTION_EXP = new Function() {
 | 
			
		||||
        @Override
 | 
			
		||||
        protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
            return params.length == 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
            boolean takeReciprocal = params[0].signum() == -1;
 | 
			
		||||
            params[0] = FUNCTION_ABS.apply(params[0]);
 | 
			
		||||
            NumberInterface sum = sumSeries(params[0], StandardPlugin::getExpSeriesTerm, getNTermsExp(getMaxError(params[0]), params[0]));
 | 
			
		||||
            if(takeReciprocal){
 | 
			
		||||
                sum = NaiveNumber.ONE.promoteTo(sum.getClass()).divide(sum);
 | 
			
		||||
            }
 | 
			
		||||
            return sum;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    public static final Function FUNCTION_LN = new Function() {
 | 
			
		||||
        @Override
 | 
			
		||||
        protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
            return params.length == 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
            NumberInterface param = params[0];
 | 
			
		||||
            int powersOf2 = 0;
 | 
			
		||||
            while(FUNCTION_ABS.apply(param.subtract(NaiveNumber.ONE.promoteTo(param.getClass()))).compareTo((new NaiveNumber(0.1)).promoteTo(param.getClass())) >= 0){
 | 
			
		||||
                if(param.subtract(NaiveNumber.ONE.promoteTo(param.getClass())).signum() == 1) {
 | 
			
		||||
                    param = param.divide(new NaiveNumber(2).promoteTo(param.getClass()));
 | 
			
		||||
                    powersOf2++;
 | 
			
		||||
                    if(param.subtract(NaiveNumber.ONE.promoteTo(param.getClass())).signum() != 1) {
 | 
			
		||||
                        break;
 | 
			
		||||
                        //No infinite loop for you.
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    param = param.multiply(new NaiveNumber(2).promoteTo(param.getClass()));
 | 
			
		||||
                    powersOf2--;
 | 
			
		||||
                    if(param.subtract(NaiveNumber.ONE.promoteTo(param.getClass())).signum() != 1) {
 | 
			
		||||
                        break;
 | 
			
		||||
                        //No infinite loop for you.
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return getLog2(param).multiply((new NaiveNumber(powersOf2)).promoteTo(param.getClass())).add(getLogPartialSum(param));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Returns the partial sum of the Taylor series for logx (around x=1).
 | 
			
		||||
         * Automatically determines the number of terms needed based on the precision of x.
 | 
			
		||||
         * @param x value at which the series is evaluated. 0 < x < 2. (x=2 is convergent but impractical.)
 | 
			
		||||
         * @return the partial sum.
 | 
			
		||||
         */
 | 
			
		||||
        private NumberInterface getLogPartialSum(NumberInterface x){
 | 
			
		||||
            NumberInterface maxError = getMaxError(x);
 | 
			
		||||
            x = x.subtract(NaiveNumber.ONE.promoteTo(x.getClass())); //Terms used are for log(x+1).
 | 
			
		||||
            NumberInterface currentTerm = x, sum = x;
 | 
			
		||||
            int n = 1;
 | 
			
		||||
            while(FUNCTION_ABS.apply(currentTerm).compareTo(maxError) > 0){
 | 
			
		||||
                n++;
 | 
			
		||||
                currentTerm = currentTerm.multiply(x).multiply((new NaiveNumber(n-1)).promoteTo(x.getClass())).divide((new NaiveNumber(n)).promoteTo(x.getClass())).negate();
 | 
			
		||||
                sum = sum.add(currentTerm);
 | 
			
		||||
            }
 | 
			
		||||
            return sum;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Returns natural log of 2 to the required precision of the class of number.
 | 
			
		||||
         * @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.
 | 
			
		||||
         */
 | 
			
		||||
        private NumberInterface getLog2(NumberInterface number){
 | 
			
		||||
            NumberInterface maxError = getMaxError(number);
 | 
			
		||||
            //NumberInterface errorBound = (new NaiveNumber(1)).promoteTo(number.getClass());
 | 
			
		||||
            //We'll use the series \sigma_{n >= 1) ((1/3^n + 1/4^n) * 1/n)
 | 
			
		||||
            //In the following, a=1/3^n, b=1/4^n, c = 1/n.
 | 
			
		||||
            //a is also an error bound.
 | 
			
		||||
            NumberInterface a = (new NaiveNumber(1)).promoteTo(number.getClass()), b = a, c = a;
 | 
			
		||||
            NumberInterface sum = NaiveNumber.ZERO.promoteTo(number.getClass());
 | 
			
		||||
            int n = 0;
 | 
			
		||||
            while(a.compareTo(maxError) >= 1){
 | 
			
		||||
                n++;
 | 
			
		||||
                a = a.divide((new NaiveNumber(3)).promoteTo(number.getClass()));
 | 
			
		||||
                b = b.divide((new NaiveNumber(4)).promoteTo(number.getClass()));
 | 
			
		||||
                c = NaiveNumber.ONE.promoteTo(number.getClass()).divide((new NaiveNumber(n)).promoteTo(number.getClass()));
 | 
			
		||||
                sum = sum.add(a.add(b).multiply(c));
 | 
			
		||||
            }
 | 
			
		||||
            return sum;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    public static final Function FUNCTION_SQRT = new Function() {
 | 
			
		||||
        @Override
 | 
			
		||||
        protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
            return params.length == 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
            return OP_CARET.getFunction().apply(params[0], ((new NaiveNumber(0.5)).promoteTo(params[0].getClass())));
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    public StandardPlugin(PluginManager manager) {
 | 
			
		||||
        super(manager);
 | 
			
		||||
    }
 | 
			
		||||
@ -25,217 +232,17 @@ public class StandardPlugin extends Plugin {
 | 
			
		||||
        registerNumber("naive", NaiveNumber.class);
 | 
			
		||||
        registerNumber("precise", PreciseNumber.class);
 | 
			
		||||
 | 
			
		||||
        registerOperator("+", new Operator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0, new Function() {
 | 
			
		||||
            @Override
 | 
			
		||||
            protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
                return params.length >= 1;
 | 
			
		||||
            }
 | 
			
		||||
        registerOperator("+", OP_ADD);
 | 
			
		||||
        registerOperator("-", OP_SUBTRACT);
 | 
			
		||||
        registerOperator("*", OP_MULTIPLY);
 | 
			
		||||
        registerOperator("/", OP_DIVIDE);
 | 
			
		||||
        registerOperator("^", OP_CARET);
 | 
			
		||||
        registerOperator("!", OP_FACTORIAL);
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
                NumberInterface sum = params[0];
 | 
			
		||||
                for(int i = 1; i < params.length; i++){
 | 
			
		||||
                    sum = sum.add(params[i]);
 | 
			
		||||
                }
 | 
			
		||||
                return sum;
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        registerOperator("-", new Operator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0, new Function() {
 | 
			
		||||
            @Override
 | 
			
		||||
            protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
                return params.length == 2;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
                return params[0].subtract(params[1]);
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        registerOperator("*", new Operator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX,1, new Function() {
 | 
			
		||||
            @Override
 | 
			
		||||
            protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
                return params.length >= 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
                NumberInterface product = params[0];
 | 
			
		||||
                for(int i = 1; i < params.length; i++){
 | 
			
		||||
                    product = product.multiply(params[i]);
 | 
			
		||||
                }
 | 
			
		||||
                return product;
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        registerOperator("/", new Operator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX,1, new Function() {
 | 
			
		||||
            @Override
 | 
			
		||||
            protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
                return params.length == 2;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
                return params[0].divide(params[1]);
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        registerOperator("^", new Operator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2, new Function() {
 | 
			
		||||
            @Override
 | 
			
		||||
            protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
                return params.length == 2;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
                return StandardPlugin.this.getFunction("exp").apply(StandardPlugin.this.getFunction("ln").apply(params[0]).multiply(params[1]));
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        registerOperator("!", new Operator(OperatorAssociativity.RIGHT, OperatorType.UNARY_POSTFIX, 0, new Function() {
 | 
			
		||||
            //private HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>> storedList = new HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>>();
 | 
			
		||||
            @Override
 | 
			
		||||
            protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
                return params.length == 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
                if(params[0].signum() == 0){
 | 
			
		||||
                    return (new NaiveNumber(1)).promoteTo(params[0].getClass());
 | 
			
		||||
                }
 | 
			
		||||
                NumberInterface factorial = params[0];
 | 
			
		||||
                NumberInterface multiplier = params[0];
 | 
			
		||||
                //It is necessary to later prevent calls of factorial on anything but non-negative integers.
 | 
			
		||||
                while((multiplier = multiplier.subtract(NaiveNumber.ONE.promoteTo(multiplier.getClass()))).signum() == 1){
 | 
			
		||||
                    factorial = factorial.multiply(multiplier);
 | 
			
		||||
                }
 | 
			
		||||
                return factorial;
 | 
			
		||||
                /*if(!storedList.containsKey(params[0].getClass())){
 | 
			
		||||
                    storedList.put(params[0].getClass(), new ArrayList<NumberInterface>());
 | 
			
		||||
                    storedList.get(params[0].getClass()).add(NaiveNumber.ONE.promoteTo(params[0].getClass()));
 | 
			
		||||
                    storedList.get(params[0].getClass()).add(NaiveNumber.ONE.promoteTo(params[0].getClass()));
 | 
			
		||||
                }*/
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        registerFunction("abs", new Function() {
 | 
			
		||||
            @Override
 | 
			
		||||
            protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
                return params.length == 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
                return params[0].multiply((new NaiveNumber(params[0].signum())).promoteTo(params[0].getClass()));
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        registerFunction("exp", new Function() {
 | 
			
		||||
            @Override
 | 
			
		||||
            protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
                return params.length == 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
                boolean takeReciprocal = params[0].signum() == -1;
 | 
			
		||||
                params[0] = StandardPlugin.this.getFunction("abs").apply(params[0]);
 | 
			
		||||
                NumberInterface sum = sumSeries(params[0], StandardPlugin.this::getExpSeriesTerm, getNTermsExp(getMaxError(params[0]), params[0]));
 | 
			
		||||
                if(takeReciprocal){
 | 
			
		||||
                    sum = NaiveNumber.ONE.promoteTo(sum.getClass()).divide(sum);
 | 
			
		||||
                }
 | 
			
		||||
                return sum;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        registerFunction("ln", new Function() {
 | 
			
		||||
            @Override
 | 
			
		||||
            protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
                return params.length == 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
                NumberInterface param = params[0];
 | 
			
		||||
                int powersOf2 = 0;
 | 
			
		||||
                while(StandardPlugin.this.getFunction("abs").apply(param.subtract(NaiveNumber.ONE.promoteTo(param.getClass()))).compareTo((new NaiveNumber(0.1)).promoteTo(param.getClass())) >= 0){
 | 
			
		||||
                    if(param.subtract(NaiveNumber.ONE.promoteTo(param.getClass())).signum() == 1) {
 | 
			
		||||
                        param = param.divide(new NaiveNumber(2).promoteTo(param.getClass()));
 | 
			
		||||
                        powersOf2++;
 | 
			
		||||
                        if(param.subtract(NaiveNumber.ONE.promoteTo(param.getClass())).signum() != 1) {
 | 
			
		||||
                            break;
 | 
			
		||||
                            //No infinite loop for you.
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        param = param.multiply(new NaiveNumber(2).promoteTo(param.getClass()));
 | 
			
		||||
                        powersOf2--;
 | 
			
		||||
                        if(param.subtract(NaiveNumber.ONE.promoteTo(param.getClass())).signum() != 1) {
 | 
			
		||||
                            break;
 | 
			
		||||
                            //No infinite loop for you.
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                return getLog2(param).multiply((new NaiveNumber(powersOf2)).promoteTo(param.getClass())).add(getLogPartialSum(param));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Returns the partial sum of the Taylor series for logx (around x=1).
 | 
			
		||||
             * Automatically determines the number of terms needed based on the precision of x.
 | 
			
		||||
             * @param x value at which the series is evaluated. 0 < x < 2. (x=2 is convergent but impractical.)
 | 
			
		||||
             * @return the partial sum.
 | 
			
		||||
             */
 | 
			
		||||
            private NumberInterface getLogPartialSum(NumberInterface x){
 | 
			
		||||
                NumberInterface maxError = StandardPlugin.this.getMaxError(x);
 | 
			
		||||
                x = x.subtract(NaiveNumber.ONE.promoteTo(x.getClass())); //Terms used are for log(x+1).
 | 
			
		||||
                NumberInterface currentTerm = x, sum = x;
 | 
			
		||||
                int n = 1;
 | 
			
		||||
                while(StandardPlugin.this.getFunction("abs").apply(currentTerm).compareTo(maxError) > 0){
 | 
			
		||||
                    n++;
 | 
			
		||||
                    currentTerm = currentTerm.multiply(x).multiply((new NaiveNumber(n-1)).promoteTo(x.getClass())).divide((new NaiveNumber(n)).promoteTo(x.getClass())).negate();
 | 
			
		||||
                    sum = sum.add(currentTerm);
 | 
			
		||||
                }
 | 
			
		||||
                return sum;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Returns natural log of 2 to the required precision of the class of number.
 | 
			
		||||
             * @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.
 | 
			
		||||
             */
 | 
			
		||||
            private NumberInterface getLog2(NumberInterface number){
 | 
			
		||||
                NumberInterface maxError = StandardPlugin.this.getMaxError(number);
 | 
			
		||||
                //NumberInterface errorBound = (new NaiveNumber(1)).promoteTo(number.getClass());
 | 
			
		||||
                //We'll use the series \sigma_{n >= 1) ((1/3^n + 1/4^n) * 1/n)
 | 
			
		||||
                //In the following, a=1/3^n, b=1/4^n, c = 1/n.
 | 
			
		||||
                //a is also an error bound.
 | 
			
		||||
                NumberInterface a = (new NaiveNumber(1)).promoteTo(number.getClass()), b = a, c = a;
 | 
			
		||||
                NumberInterface sum = NaiveNumber.ZERO.promoteTo(number.getClass());
 | 
			
		||||
                int n = 0;
 | 
			
		||||
                while(a.compareTo(maxError) >= 1){
 | 
			
		||||
                    n++;
 | 
			
		||||
                    a = a.divide((new NaiveNumber(3)).promoteTo(number.getClass()));
 | 
			
		||||
                    b = b.divide((new NaiveNumber(4)).promoteTo(number.getClass()));
 | 
			
		||||
                    c = NaiveNumber.ONE.promoteTo(number.getClass()).divide((new NaiveNumber(n)).promoteTo(number.getClass()));
 | 
			
		||||
                    sum = sum.add(a.add(b).multiply(c));
 | 
			
		||||
                }
 | 
			
		||||
                return sum;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        registerFunction("sqrt", new Function() {
 | 
			
		||||
            @Override
 | 
			
		||||
            protected boolean matchesParams(NumberInterface[] params) {
 | 
			
		||||
                return params.length == 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            protected NumberInterface applyInternal(NumberInterface[] params) {
 | 
			
		||||
                return StandardPlugin.this.getOperator("^").getFunction().apply(params[0], ((new NaiveNumber(0.5)).promoteTo(params[0].getClass())));
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        registerFunction("abs", FUNCTION_ABS);
 | 
			
		||||
        registerFunction("exp", FUNCTION_EXP);
 | 
			
		||||
        registerFunction("ln", FUNCTION_LN);
 | 
			
		||||
        registerFunction("sqrt",FUNCTION_SQRT);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@ -249,8 +256,8 @@ public class StandardPlugin extends Plugin {
 | 
			
		||||
     * @param x the real number at which the series is evaluated.
 | 
			
		||||
     * @return the nth term of the series.
 | 
			
		||||
     */
 | 
			
		||||
    private NumberInterface getExpSeriesTerm(int n, NumberInterface x){
 | 
			
		||||
        return x.intPow(n).divide(this.getOperator("!").getFunction().apply((new NaiveNumber(n)).promoteTo(x.getClass())));
 | 
			
		||||
    private static NumberInterface getExpSeriesTerm(int n, NumberInterface x){
 | 
			
		||||
        return x.intPow(n).divide(OP_FACTORIAL.getFunction().apply((new NaiveNumber(n)).promoteTo(x.getClass())));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -260,11 +267,11 @@ public class StandardPlugin extends Plugin {
 | 
			
		||||
     * @param x where the function is evaluated.
 | 
			
		||||
     * @return the number of terms needed to evaluated the exponential function.
 | 
			
		||||
     */
 | 
			
		||||
    private int getNTermsExp(NumberInterface maxError, NumberInterface x) {
 | 
			
		||||
    private static int getNTermsExp(NumberInterface maxError, NumberInterface x) {
 | 
			
		||||
        //We need n such that |x^(n+1)| <= (n+1)! * maxError
 | 
			
		||||
        //The variables LHS and RHS refer to the above inequality.
 | 
			
		||||
        int n = 0;
 | 
			
		||||
        x = this.getFunction("abs").apply(x);
 | 
			
		||||
        x = FUNCTION_ABS.apply(x);
 | 
			
		||||
        NumberInterface LHS = x, RHS = maxError;
 | 
			
		||||
        while (LHS.compareTo(RHS) > 0) {
 | 
			
		||||
            n++;
 | 
			
		||||
@ -282,7 +289,7 @@ public class StandardPlugin extends Plugin {
 | 
			
		||||
     * @param n the number of terms in the partial sum.
 | 
			
		||||
     * @return the value of the partial sum that has the same class as x.
 | 
			
		||||
     */
 | 
			
		||||
    private NumberInterface sumSeries(NumberInterface x, BiFunction<Integer, NumberInterface, NumberInterface> nthTermFunction, int n){
 | 
			
		||||
    private static NumberInterface sumSeries(NumberInterface x, BiFunction<Integer, NumberInterface, NumberInterface> nthTermFunction, int n){
 | 
			
		||||
        NumberInterface sum = NaiveNumber.ZERO.promoteTo(x.getClass());
 | 
			
		||||
        for(int i = 0; i <= n; i++){
 | 
			
		||||
            sum = sum.add(nthTermFunction.apply(i, x));
 | 
			
		||||
@ -295,7 +302,7 @@ public class StandardPlugin extends Plugin {
 | 
			
		||||
     * @param number Any instance of the NumberInterface in question (should return an appropriate precision).
 | 
			
		||||
     * @return the maximum error.
 | 
			
		||||
     */
 | 
			
		||||
    private NumberInterface getMaxError(NumberInterface number){
 | 
			
		||||
    private static NumberInterface getMaxError(NumberInterface number){
 | 
			
		||||
        return (new NaiveNumber(10)).promoteTo(number.getClass()).intPow(-number.getMaxPrecision());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user