1
0
mirror of https://github.com/DanilaFe/abacus synced 2026-01-26 00:25:20 +00:00

Compare commits

...

7 Commits

Author SHA1 Message Date
Arthur Drobot
f97d16c640 Comment out debugging output. 2017-07-31 23:09:11 -07:00
Arthur Drobot
a0bba03c2c Separate power and factorial calculations to fix large precision loss in exp. 2017-07-31 22:56:55 -07:00
Arthur Drobot
8666e96420 Remove unused code and functions in StandardPlugin. 2017-07-31 14:53:41 -07:00
Arthur Drobot
fd40e6b297 Rewrite exp. (Now works faster.) Add private factorial function to StandardPlugin as well. 2017-07-31 14:49:25 -07:00
Arthur Drobot
79ccd61af3 Add ceiling to NumberInterface and the two numbers that implement it. 2017-07-31 13:25:23 -07:00
Arthur Drobot
699ba9e193 Merge branch 'master' of https://github.com/DanilaFe/abacus 2017-07-31 12:40:19 -07:00
Arthur Drobot
e43f223086 Optimize log. 2017-07-31 12:39:56 -07:00
4 changed files with 71 additions and 44 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
@@ -203,11 +230,12 @@ public class StandardPlugin extends Plugin {
private NumberInterface getLogPartialSum(NumberInterface x) { private NumberInterface getLogPartialSum(NumberInterface x) {
NumberInterface maxError = getMaxError(x); NumberInterface maxError = getMaxError(x);
x = x.subtract(NaiveNumber.ONE.promoteTo(x.getClass())); //Terms used are for log(x+1). x = x.subtract(NaiveNumber.ONE.promoteTo(x.getClass())); //Terms used are for log(x+1).
NumberInterface 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(currentTerm).compareTo(maxError) > 0) {
n++; n++;
currentTerm = currentTerm.multiply(x).multiply((new NaiveNumber(n - 1)).promoteTo(x.getClass())).divide((new NaiveNumber(n)).promoteTo(x.getClass())).negate(); currentNumerator = currentNumerator.multiply(x).negate();
currentTerm = currentNumerator.divide(new NaiveNumber(n).promoteTo(x.getClass()));
sum = sum.add(currentTerm); sum = sum.add(currentTerm);
} }
return sum; return sum;
@@ -238,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
@@ -256,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 evaluated 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.
* *
@@ -338,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);
}
} }