[
https://issues.apache.org/jira/browse/NUMBERS-175?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17444010#comment-17444010
]
Alex Herbert commented on NUMBERS-175:
--------------------------------------
Some thoughts:
Returning an Iterable of Coefficient requires materializing another class after
you have already materialized the GeneralizedContinuedFraction. Then you have
to convert the Iterable to an Iterator to use it in a loop that can be broken
at convergence.
I'd prefer to only create a single class that is the generator of the
coefficients.
I did think of the fraction using a similar pattern where the instance is
required to set A and/or B:
{code:java}
public abstract class GeneralizedContinuedFraction {
public double evaluate();
protected void setA(double a);
protected void setB(double b);
protected abstract void next();
}
{code}
This would minimise object creation overhead.
Used as:
{code:java}
double gr = new GeneralizedContinuedFraction() {
@Override
void next() {
setA(1);
setB(1);
}
}.evaluate();
{code}
If you do not set A or B then they default to 1. This would allow computation
of a simple continued fraction using:
{code:java}
// 0.84375 = [0;1,5,2,2]
double v = new GeneralizedContinuedFraction() {
double[] values = {0,1,5,2,2};
int n;
@Override
void next() {
if (n != values.length) {
setB(values[n++]);
}
setB(0);
}
}.value();
{code}
This does not address the issue of whether to include the leading coefficient
b0. In the case above it is zero so ideally the fraction should evaluate
without this.
Perhaps this can be done using a flag to the evaluate function or the abstract
class constructor.
> Add continued fraction implementations using a generator of terms
> -----------------------------------------------------------------
>
> Key: NUMBERS-175
> URL: https://issues.apache.org/jira/browse/NUMBERS-175
> Project: Commons Numbers
> Issue Type: Improvement
> Components: fraction
> Affects Versions: 1.0
> Reporter: Alex Herbert
> Priority: Minor
>
> The ContinuedFraction class allows computation of:
> {noformat}
> b0 + a1
> ------------------
> b1 + a2
> -------------
> b2 + a3
> --------
> b3 + ...{noformat}
> This is done using an abstract class that is extended to implement the
> methods to get the terms:
> {code:java}
> double getA(int n, double x);
> double getB(int n, double x);{code}
> This allows the fraction to be reused to generate results for different
> points to evaluate. However:
> * It does not lend itself to fractions where the terms can be computed using
> recursion:
> {noformat}
> b(n+1) = f( b(n) ) {noformat}
> * It requires two method calls to generate terms a_n and b_n for each
> iteration thus preventing optimisation of the computation using the input n
> for values shared between computation of a and b.
> An alternative method is to support a generator of the paired terms a_n and
> b_n:
> {code:java}
> static double continuedFraction(Supplier<double[]> gen);{code}
> To be used in a single evaluation as:
> {code:java}
> Supplier<double[]> goldenRatio = () -> return new double[] {1, 1};
> double gr = continuedFraction(goldenRatio);
> // gr = 1.61803398874...{code}
> An additional feature is to support a simple continued fraction where all
> partial numerators are 1:
> {noformat}
> b0 + 1
> ------------------
> b1 + 1
> -------------
> b2 + 1
> --------
> b3 + ...
> {noformat}
> E.g. using:
> {code:java}
> static double simpleContinuedFraction(DoubleSupplier gen); {code}
> h3. Addition
> In some situations it is an advantage to not evaluate the leading term b0.
> The term may not be part of a regular series, or may be zero:
> {noformat}
> a1
> ------------------
> b1 + a2
> -------------
> b2 + a3
> --------
> b3 + ...
> {noformat}
> h3. API
> Using the nomeclature from Wikipedia and Wolfram suggests the following:
> {code:java}
> public static final class GeneralizedContinuedFraction {
> /**
> * Evaluate the continued fraction from the generator for partial
> numerator
> * a and partial denominator b.
> * <pre>
> * b0 + a1
> * ------------------
> * b1 + a2
> * -------------
> * b2 + a3
> * --------
> * b3 + ...
> * </pre>
> *
> * <p>Note: The first generated partial numerator a0 is discarded.
> *
> * @param gen Generator
> * @return the continued fraction value
> */
> public static double value(Supplier<double[]> gen);
> /**
> * Evaluate the continued fraction from the generator for partial
> numerator
> * a and partial denominator b.
> * <pre>
> * a1
> * ------------------
> * b1 + a2
> * -------------
> * b2 + a3
> * --------
> * b3 + ...
> * </pre>
> *
> * <p>Note: Both of the first terms a and b are used.
> *
> * @param gen Generator
> * @return the continued fraction value
> */
> public static double valueA(Supplier<double[]> gen);
> }
> public static final class SimpleContinuedFraction {
> public static double value(DoubleSupplier gen);
> public static double valueA(DoubleSupplier gen);
> }
> {code}
> The API should support the optional parameters to control the convergence
> tolerance and the maximum number of iterations.
> The variant to evaluate without the leading b0 term is not essential. It can
> be evaluated by starting the generator at the next iteration using:
> {code:java}
> Supplier<double[]> gen = ...; // Start at terms (a1,b1)
> // Evaluation will discard a1;
> // this value (separately computed) is then used to compute the result
> double value = a1 / GeneralizedContinuedFraction.value(gen);{code}
> This variant is present in the Boost c++ library and used to evaluate terms
> for the gamma function.
> See:
> [https://en.wikipedia.org/wiki/Continued_fraction]
> [https://mathworld.wolfram.com/SimpleContinuedFraction.html]
> [https://mathworld.wolfram.com/GeneralizedContinuedFraction.html]
> [Boost Continued Fraction (v
> 1_77_0)|https://www.boost.org/doc/libs/1_77_0/libs/math/doc/html/math_toolkit/internals/cf.html]
>
--
This message was sent by Atlassian Jira
(v8.20.1#820001)