1
0
mirror of https://github.com/DanilaFe/abacus synced 2024-12-24 08:12:39 -08:00

Implement a getPi function for the plugin, and use the new pi value.

This commit is contained in:
Danila Fedorin 2017-08-04 09:55:24 -07:00
parent b06e9fcbee
commit 276b6719fd
3 changed files with 36 additions and 46 deletions

View File

@ -1,7 +1,6 @@
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 {
@ -9,15 +8,15 @@ public class PreciseNumber implements NumberInterface {
/** /**
* The number one. * The number one.
*/ */
static final PreciseNumber ONE = new PreciseNumber(BigDecimal.ONE); public static final PreciseNumber ONE = new PreciseNumber(BigDecimal.ONE);
/** /**
* The number zero. * The number zero.
*/ */
static final PreciseNumber ZERO = new PreciseNumber(BigDecimal.ZERO); public static final PreciseNumber ZERO = new PreciseNumber(BigDecimal.ZERO);
/** /**
* The number ten. * The number ten.
*/ */
static final PreciseNumber TEN = new PreciseNumber(BigDecimal.TEN); public static final PreciseNumber TEN = new PreciseNumber(BigDecimal.TEN);
/** /**
* The value of the PreciseNumber. * The value of the PreciseNumber.

View File

@ -2,6 +2,7 @@ package org.nwapw.abacus.plugin;
import org.nwapw.abacus.function.Function; import org.nwapw.abacus.function.Function;
import org.nwapw.abacus.function.Operator; import org.nwapw.abacus.function.Operator;
import org.nwapw.abacus.number.NumberInterface;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -177,6 +178,10 @@ public abstract class Plugin {
return manager.numberImplementationFor(name); return manager.numberImplementationFor(name);
} }
protected final NumberInterface getPi(Class<? extends NumberInterface> forClass){
return manager.interfaceImplementationFor(forClass).instanceForPi();
}
/** /**
* Abstract method to be overridden by plugin implementation, in which the plugins * Abstract method to be overridden by plugin implementation, in which the plugins
* are supposed to register the functions they provide and do any other * are supposed to register the functions they provide and do any other

View File

@ -19,7 +19,6 @@ 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>>(); private static HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>> factorialLists = new HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>>();
static HashMap<Class<? extends NumberInterface>, NumberInterface> piValues = new HashMap<Class<? extends NumberInterface>, NumberInterface>();
/** /**
* The addition operator, + * The addition operator, +
@ -284,7 +283,7 @@ public class StandardPlugin extends Plugin {
/** /**
* The sine function (the argument is interpreted in radians). * The sine function (the argument is interpreted in radians).
*/ */
public static final Function FUNCTION_SIN = new Function() { public final Function functionSin = new Function() {
@Override @Override
protected boolean matchesParams(NumberInterface[] params) { protected boolean matchesParams(NumberInterface[] params) {
return params.length == 1; return params.length == 1;
@ -294,7 +293,7 @@ public class StandardPlugin extends Plugin {
protected NumberInterface applyInternal(NumberInterface[] params) { protected NumberInterface applyInternal(NumberInterface[] params) {
NumberInterface pi = getPi(params[0].getClass()); NumberInterface pi = getPi(params[0].getClass());
NumberInterface twoPi = pi.multiply(new NaiveNumber(2).promoteTo(pi.getClass())); NumberInterface twoPi = pi.multiply(new NaiveNumber(2).promoteTo(pi.getClass()));
NumberInterface theta = getSmallAngle(params[0]); NumberInterface theta = getSmallAngle(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);
@ -327,7 +326,29 @@ public class StandardPlugin extends Plugin {
@Override @Override
public NumberInterface instanceForPi() { public NumberInterface instanceForPi() {
return null; NumberInterface C = FUNCTION_SQRT.apply(new PreciseNumber("10005")).multiply(new PreciseNumber("426880"));
NumberInterface M = PreciseNumber.ONE;
NumberInterface L = new PreciseNumber("13591409");
NumberInterface X = M;
NumberInterface sum = L;
int termsNeeded = C.getMaxPrecision()/13 + 1;
NumberInterface lSummand = new PreciseNumber("545140134");
NumberInterface xMultiplier = new PreciseNumber("262537412")
.multiply(new PreciseNumber("1000000000"))
.add(new PreciseNumber("640768000"))
.negate();
for(int i = 0; i < termsNeeded; i++){
M = M
.multiply(new NaiveNumber(12*i+2).promoteTo(PreciseNumber.class))
.multiply(new NaiveNumber(12*i+6).promoteTo(PreciseNumber.class))
.multiply(new NaiveNumber(12*i+10).promoteTo(PreciseNumber.class))
.divide(new NaiveNumber(Math.pow(i+1,3)).promoteTo(PreciseNumber.class));
L = L.add(lSummand);
X = X.multiply(xMultiplier);
sum = sum.add(M.multiply(L).divide(X));
}
return C.divide(sum);
} }
}; };
@ -377,7 +398,7 @@ public class StandardPlugin extends Plugin {
registerFunction("exp", FUNCTION_EXP); registerFunction("exp", FUNCTION_EXP);
registerFunction("ln", FUNCTION_LN); registerFunction("ln", FUNCTION_LN);
registerFunction("sqrt", FUNCTION_SQRT); registerFunction("sqrt", FUNCTION_SQRT);
registerFunction("sin", FUNCTION_SIN); registerFunction("sin", functionSin);
} }
@Override @Override
@ -425,48 +446,13 @@ public class StandardPlugin extends Plugin {
return sum; return sum;
} }
/**
* Returns an approximation of Pi, with appropriate accuracy for given number class.
* @param numClass type of number.
* @return A number of class numClass, with value approximately Pi = 3.1415...
*/
public static NumberInterface getPi(Class<? extends NumberInterface> numClass){
if(!piValues.containsKey(numClass)){
//https://en.wikipedia.org/wiki/Chudnovsky_algorithm
NumberInterface C = FUNCTION_SQRT.apply(new NaiveNumber(10005).promoteTo(numClass)).multiply(new NaiveNumber(426880).promoteTo(numClass));
NumberInterface M = NaiveNumber.ONE.promoteTo(numClass);
NumberInterface L = new NaiveNumber(13591409).promoteTo(numClass);
NumberInterface X = M;
NumberInterface sum = L;
int termsNeeded = C.getMaxPrecision()/13 + 1;
NumberInterface lSummand = new NaiveNumber(545140134).promoteTo(L.getClass());
NumberInterface xMultiplier = new NaiveNumber(262537412).promoteTo(X.getClass())
.multiply(new NaiveNumber(1000000000).promoteTo(X.getClass()))
.add(new NaiveNumber(640768000).promoteTo(X.getClass()))
.negate();
for(int i = 0; i < termsNeeded; i++){
M = M
.multiply(new NaiveNumber(12*i+2).promoteTo(M.getClass()))
.multiply(new NaiveNumber(12*i+6).promoteTo(M.getClass()))
.multiply(new NaiveNumber(12*i+10).promoteTo(M.getClass()))
.divide(new NaiveNumber(Math.pow(i+1,3)).promoteTo(M.getClass()));
L = L.add(lSummand);
X = X.multiply(xMultiplier);
sum = sum.add(M.multiply(L).divide(X));
}
piValues.put(numClass, C.divide(sum));
}
return piValues.get(numClass);
}
/** /**
* Returns an equivalent angle in the interval [0, 2pi) * Returns an equivalent angle in the interval [0, 2pi)
* @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){ private static NumberInterface getSmallAngle(NumberInterface phi, NumberInterface pi){
NumberInterface twoPi = getPi(phi.getClass()).multiply(new NaiveNumber("2").promoteTo(phi.getClass())); NumberInterface twoPi = pi.multiply(new NaiveNumber("2").promoteTo(phi.getClass()));
NumberInterface theta = FUNCTION_ABS.apply(phi).subtract(twoPi NumberInterface theta = FUNCTION_ABS.apply(phi).subtract(twoPi
.multiply(FUNCTION_ABS.apply(phi).divide(twoPi).floor())); //Now theta is in [0, 2pi). .multiply(FUNCTION_ABS.apply(phi).divide(twoPi).floor())); //Now theta is in [0, 2pi).
if(phi.signum() < 0){ if(phi.signum() < 0){