From e04caee942b2e74884813a9a3dd1fe2a3d591fa6 Mon Sep 17 00:00:00 2001 From: Arthur Drobot Date: Thu, 27 Jul 2017 10:03:26 -0700 Subject: [PATCH 1/7] Add absolute value function to standard plugin. Modify getNTermsExp to work on negative exponents instead (and correctly). --- .../nwapw/abacus/plugin/StandardPlugin.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/org/nwapw/abacus/plugin/StandardPlugin.java b/src/org/nwapw/abacus/plugin/StandardPlugin.java index 9881ff2..ac4eb76 100755 --- a/src/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/src/org/nwapw/abacus/plugin/StandardPlugin.java @@ -75,6 +75,7 @@ public class StandardPlugin extends Plugin { }); registerFunction("!", new Function() { + //private ArrayLi @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -95,6 +96,18 @@ public class StandardPlugin extends Plugin { } }); + 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) { @@ -126,14 +139,15 @@ public class StandardPlugin extends Plugin { * @return */ private int getNTermsExp(NumberInterface maxError, NumberInterface x){ - //We need n such that x^(n+2) <= (n+1)! * maxError + //We need n such that |x^(n+1)| <= (n+1)! * maxError //The variables LHS and RHS refer to the above inequality. int n = 0; - NumberInterface LHS = x.intPow(2), RHS = maxError; + x = this.getFunction("abs").apply(x); + NumberInterface LHS = x, RHS = maxError; while(LHS.compareTo(RHS) > 0){ n++; LHS = LHS.multiply(x); - RHS = RHS.multiply(new NaiveNumber(n).promoteTo(RHS.getClass())); + RHS = RHS.multiply(new NaiveNumber(n+1).promoteTo(RHS.getClass())); } return n; } From ea648b38e751a3a9f9731d3b3e96889fdffffd10 Mon Sep 17 00:00:00 2001 From: Arthur Drobot Date: Thu, 27 Jul 2017 10:16:38 -0700 Subject: [PATCH 2/7] Modify exp to work properly with the new changes and support all reals. --- src/org/nwapw/abacus/plugin/StandardPlugin.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/org/nwapw/abacus/plugin/StandardPlugin.java b/src/org/nwapw/abacus/plugin/StandardPlugin.java index ac4eb76..694fcda 100755 --- a/src/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/src/org/nwapw/abacus/plugin/StandardPlugin.java @@ -4,6 +4,7 @@ import org.nwapw.abacus.function.Function; import org.nwapw.abacus.number.NaiveNumber; import org.nwapw.abacus.number.NumberInterface; +import javax.print.attribute.standard.MediaSize; import java.util.function.BiFunction; /** @@ -116,7 +117,13 @@ public class StandardPlugin extends Plugin { @Override protected NumberInterface applyInternal(NumberInterface[] params) { - return sumSeries(params[0], StandardPlugin.this::getExpSeriesTerm, getNTermsExp(getMaxError(params[0]), params[0])); + 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; } }); } From c15b73773849a58485482bcf74c92f2fa533bd54 Mon Sep 17 00:00:00 2001 From: Arthur Drobot Date: Thu, 27 Jul 2017 10:32:09 -0700 Subject: [PATCH 3/7] Increase precision of NaiveNumber to 18. --- src/org/nwapw/abacus/number/NaiveNumber.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/nwapw/abacus/number/NaiveNumber.java b/src/org/nwapw/abacus/number/NaiveNumber.java index 5bd3cb0..b201a91 100755 --- a/src/org/nwapw/abacus/number/NaiveNumber.java +++ b/src/org/nwapw/abacus/number/NaiveNumber.java @@ -29,7 +29,7 @@ public class NaiveNumber implements NumberInterface { @Override public int precision() { - return 15; + return 18; } @Override From 18a5a99887c670120d18519426514b4f0ef551e9 Mon Sep 17 00:00:00 2001 From: Arthur Drobot Date: Thu, 27 Jul 2017 13:04:41 -0700 Subject: [PATCH 4/7] Add natural log function. May not be terribly efficient currently, but it works and is usable. --- .../nwapw/abacus/plugin/StandardPlugin.java | 81 ++++++++++++++++++- 1 file changed, 78 insertions(+), 3 deletions(-) diff --git a/src/org/nwapw/abacus/plugin/StandardPlugin.java b/src/org/nwapw/abacus/plugin/StandardPlugin.java index 694fcda..5772762 100755 --- a/src/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/src/org/nwapw/abacus/plugin/StandardPlugin.java @@ -126,6 +126,81 @@ public class StandardPlugin extends Plugin { 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; + } + }); } /** @@ -145,16 +220,16 @@ public class StandardPlugin extends Plugin { * @param x where the function is evaluated. * @return */ - private int getNTermsExp(NumberInterface maxError, NumberInterface x){ + private 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); NumberInterface LHS = x, RHS = maxError; - while(LHS.compareTo(RHS) > 0){ + while (LHS.compareTo(RHS) > 0) { n++; LHS = LHS.multiply(x); - RHS = RHS.multiply(new NaiveNumber(n+1).promoteTo(RHS.getClass())); + RHS = RHS.multiply(new NaiveNumber(n + 1).promoteTo(RHS.getClass())); } return n; } From 950e3503b7136c806352001f67c456a9f34695d9 Mon Sep 17 00:00:00 2001 From: Arthur Drobot Date: Thu, 27 Jul 2017 13:17:22 -0700 Subject: [PATCH 5/7] Add pow function. --- src/org/nwapw/abacus/plugin/StandardPlugin.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/org/nwapw/abacus/plugin/StandardPlugin.java b/src/org/nwapw/abacus/plugin/StandardPlugin.java index 5772762..d48beb7 100755 --- a/src/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/src/org/nwapw/abacus/plugin/StandardPlugin.java @@ -201,6 +201,18 @@ public class StandardPlugin extends Plugin { return sum; } }); + + registerFunction("pow", 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])); + } + }); } /** From 22f8a48195c60f969161dc92bdcb3d7344daf7b1 Mon Sep 17 00:00:00 2001 From: Arthur Drobot Date: Thu, 27 Jul 2017 13:39:19 -0700 Subject: [PATCH 6/7] Begin working on memoization for factorial. (Commented out for now.) --- src/org/nwapw/abacus/plugin/StandardPlugin.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/org/nwapw/abacus/plugin/StandardPlugin.java b/src/org/nwapw/abacus/plugin/StandardPlugin.java index d48beb7..76d7826 100755 --- a/src/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/src/org/nwapw/abacus/plugin/StandardPlugin.java @@ -5,6 +5,8 @@ import org.nwapw.abacus.number.NaiveNumber; import org.nwapw.abacus.number.NumberInterface; import javax.print.attribute.standard.MediaSize; +import java.util.ArrayList; +import java.util.HashMap; import java.util.function.BiFunction; /** @@ -76,7 +78,7 @@ public class StandardPlugin extends Plugin { }); registerFunction("!", new Function() { - //private ArrayLi + //private HashMap, ArrayList> storedList = new HashMap, ArrayList>(); @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -94,6 +96,11 @@ public class StandardPlugin extends Plugin { factorial = factorial.multiply(multiplier); } return factorial; + /*if(!storedList.containsKey(params[0].getClass())){ + storedList.put(params[0].getClass(), new ArrayList()); + storedList.get(params[0].getClass()).add(NaiveNumber.ONE.promoteTo(params[0].getClass())); + storedList.get(params[0].getClass()).add(NaiveNumber.ONE.promoteTo(params[0].getClass())); + }*/ } }); From 8fb82e1fb8f8d2a57e9891d54d2c5a169459831b Mon Sep 17 00:00:00 2001 From: Arthur Drobot Date: Thu, 27 Jul 2017 13:47:51 -0700 Subject: [PATCH 7/7] Add sqrt function. --- src/org/nwapw/abacus/plugin/StandardPlugin.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/org/nwapw/abacus/plugin/StandardPlugin.java b/src/org/nwapw/abacus/plugin/StandardPlugin.java index 76d7826..8058e49 100755 --- a/src/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/src/org/nwapw/abacus/plugin/StandardPlugin.java @@ -220,6 +220,18 @@ public class StandardPlugin extends Plugin { return StandardPlugin.this.getFunction("exp").apply(StandardPlugin.this.getFunction("ln").apply(params[0]).multiply(params[1])); } }); + + registerFunction("sqrt", new Function() { + @Override + protected boolean matchesParams(NumberInterface[] params) { + return params.length == 1; + } + + @Override + protected NumberInterface applyInternal(NumberInterface[] params) { + return StandardPlugin.this.getFunction("pow").apply(params[0], (new NaiveNumber(0.5))); + } + }); } /**