1
0
mirror of https://github.com/DanilaFe/abacus synced 2026-01-25 16:15:19 +00:00

Compare commits

...

5 Commits

4 changed files with 68 additions and 42 deletions

View File

@@ -93,6 +93,11 @@ public class NaiveNumber implements NumberInterface {
return this.compareTo(ZERO); return this.compareTo(ZERO);
} }
@Override
public int ceiling() {
return (int) Math.ceil(value);
}
@Override @Override
public NumberInterface promoteTo(Class<? extends NumberInterface> toClass) { public NumberInterface promoteTo(Class<? extends NumberInterface> toClass) {
if (toClass == this.getClass()) return this; if (toClass == this.getClass()) return this;

View File

@@ -79,6 +79,12 @@ public interface NumberInterface {
*/ */
int signum(); int signum();
/**
* Returns the least integer greater than or equal to the number.
* @return the least integer >= the number, if int can hold the value.
*/
int ceiling();
/** /**
* Promotes this class to another number class. * Promotes this class to another number class.
* *

View File

@@ -1,6 +1,7 @@
package org.nwapw.abacus.number; package org.nwapw.abacus.number;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode; import java.math.RoundingMode;
public class PreciseNumber implements NumberInterface { public class PreciseNumber implements NumberInterface {
@@ -49,7 +50,7 @@ public class PreciseNumber implements NumberInterface {
@Override @Override
public NumberInterface multiply(NumberInterface multiplier) { public NumberInterface multiply(NumberInterface multiplier) {
return new PreciseNumber(value.multiply(((PreciseNumber) multiplier).value)); return new PreciseNumber(this.value.multiply(((PreciseNumber) multiplier).value));
} }
@Override @Override
@@ -94,6 +95,11 @@ public class PreciseNumber implements NumberInterface {
return value.signum(); return value.signum();
} }
@Override
public int ceiling() {
return (int) Math.ceil(value.doubleValue());
}
@Override @Override
public NumberInterface negate() { public NumberInterface negate() {
return new PreciseNumber(value.negate()); return new PreciseNumber(value.negate());

View File

@@ -8,6 +8,8 @@ import org.nwapw.abacus.number.NaiveNumber;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.number.PreciseNumber; import org.nwapw.abacus.number.PreciseNumber;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.function.BiFunction; import java.util.function.BiFunction;
/** /**
@@ -16,6 +18,8 @@ import java.util.function.BiFunction;
*/ */
public class StandardPlugin extends Plugin { public class StandardPlugin extends Plugin {
private static HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>> factorialLists = new HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>>();
/** /**
* The addition operator, + * The addition operator, +
*/ */
@@ -152,17 +156,40 @@ public class StandardPlugin extends Plugin {
@Override @Override
protected NumberInterface applyInternal(NumberInterface[] params) { protected NumberInterface applyInternal(NumberInterface[] params) {
boolean takeReciprocal = params[0].signum() == -1; NumberInterface maxError = getMaxError(params[0]);
params[0] = FUNCTION_ABS.apply(params[0]); int n = 0;
NumberInterface sum = sumSeries(params[0], StandardPlugin::getExpSeriesTerm, getNTermsExp(getMaxError(params[0]), params[0])); if(params[0].signum() <= 0){
if (takeReciprocal) { NumberInterface currentTerm = NaiveNumber.ONE.promoteTo(params[0].getClass()), sum = currentTerm;
sum = NaiveNumber.ONE.promoteTo(sum.getClass()).divide(sum); while(FUNCTION_ABS.apply(currentTerm).compareTo(maxError) > 0){
n++;
currentTerm = currentTerm.multiply(params[0]).divide((new NaiveNumber(n)).promoteTo(params[0].getClass()));
sum = sum.add(currentTerm);
}
return sum;
}
else{
//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.
NumberInterface sum = NaiveNumber.ONE.promoteTo(params[0].getClass());
NumberInterface nextNumerator = params[0];
NumberInterface left = params[0].multiply((new NaiveNumber(3)).promoteTo(params[0].getClass()).intPow(params[0].ceiling())), right = maxError;
do{
sum = sum.add(nextNumerator.divide(factorial(params[0].getClass(), n+1)));
n++;
nextNumerator = nextNumerator.multiply(params[0]);
left = left.multiply(params[0]);
NumberInterface nextN = (new NaiveNumber(n+1)).promoteTo(params[0].getClass());
right = right.multiply(nextN);
//System.out.println(left + ", " + right);
}
while(left.compareTo(right) > 0);
//System.out.println(n+1);
return sum;
} }
return sum;
} }
}; };
/** /**
* The natural log function, ln(exp(1)) = 1 * The natural log function.
*/ */
public static final Function FUNCTION_LN = new Function() { public static final Function FUNCTION_LN = new Function() {
@Override @Override
@@ -239,7 +266,7 @@ public class StandardPlugin extends Plugin {
} }
}; };
/** /**
* The square root function, sqrt(4) = 2 * The square root function.
*/ */
public static final Function FUNCTION_SQRT = new Function() { public static final Function FUNCTION_SQRT = new Function() {
@Override @Override
@@ -257,39 +284,6 @@ public class StandardPlugin extends Plugin {
super(manager); super(manager);
} }
/**
* Returns the nth term of the Taylor series (centered at 0) of e^x
*
* @param n the term required (n >= 0).
* @param x the real number at which the series is evaluated.
* @return the nth term of the series.
*/
private static NumberInterface getExpSeriesTerm(int n, NumberInterface x) {
return x.intPow(n).divide(OP_FACTORIAL.getFunction().apply((new NaiveNumber(n)).promoteTo(x.getClass())));
}
/**
* Returns the number of terms needed to evaluate the exponential function (at x)
* such that the error is at most maxError.
*
* @param maxError Maximum error permissible (This should probably be positive.)
* @param x where the function is evaluated.
* @return the number of terms needed to evaluate the exponential function.
*/
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 = FUNCTION_ABS.apply(x);
NumberInterface LHS = x, RHS = maxError;
while (LHS.compareTo(RHS) > 0) {
n++;
LHS = LHS.multiply(x);
RHS = RHS.multiply(new NaiveNumber(n + 1).promoteTo(RHS.getClass()));
}
return n;
}
/** /**
* Returns a partial sum of a series whose terms are given by the nthTermFunction, evaluated at x. * Returns a partial sum of a series whose terms are given by the nthTermFunction, evaluated at x.
* *
@@ -339,4 +333,19 @@ public class StandardPlugin extends Plugin {
} }
public static NumberInterface factorial(Class<? extends NumberInterface> numberClass, int n){
if(!factorialLists.containsKey(numberClass)){
factorialLists.put(numberClass, new ArrayList<NumberInterface>());
factorialLists.get(numberClass).add(NaiveNumber.ONE.promoteTo(numberClass));
factorialLists.get(numberClass).add(NaiveNumber.ONE.promoteTo(numberClass));
}
ArrayList<NumberInterface> list = factorialLists.get(numberClass);
if(n >= list.size()){
while(list.size() < n + 16){
list.add(list.get(list.size()-1).multiply(new NaiveNumber(list.size()).promoteTo(numberClass)));
}
}
return list.get(n);
}
} }