The algorithm uses the backward recurrence method to compute the continued fraction expansion. This method has been shown to be extremely stable for most continued fraction expansions, which is extremely important on numerical platforms that incur truncation/round-off error due to the limitations of machine precision. It can be shown that the backward recurrence method ("from tail to head") is vastly more stable (even self-correcting) than the forward recurrence method ("from head to tail") for two important classes of continued fractions: the Stieltjes continued fractions (which include the C-fractions) and those that fulfill the parabolic convergence region theorem. Several function classes with known Stieltjes continued fraction expansions include: exponential integrals, incomplete gamma functions, logarithms of gamma functions, the error function, ratios of successive Bessel functions of the first kind, Euler's hypergeometric function, as well as various elementary transcendental functions. The forward recurrence method (which solves a second-order linear difference equation), however, can be computationally more efficient due to the carry-over of results from one step to the next, which is a property the backward recurrence method does not possess.

Although the terms in the canonical contraction are more complex than the ones in the original noncontracted continued fraction expansion, the speed gain on traditional numerical platforms (Java, .Net, C) is substantial. The following uses 10,000 uniformly distributed random numbers between 3 and 20 for

and between 0 and 5 for

and outputs the computation time. As the design of the canonical contraction requires only

Floor[n/2]-1 steps to produce the same number when

steps are used in the original noncontracted continued fraction expansion,

steps are used for the function "noncontracted" to ensure both methods attain the same accuracy. To minimize any possible inaccuracies in the Java time measurement due to cycle lapses every computation is carried out 1000 times.

import java.util.Random;

public class piapprox {

final private static int factorial(final int k)

{

int kk=1;

for (int i = 1; i

k; i++) {

kk = kk * i;

}

return kk;

}

final private static int power(final int k)

{

int kk=1;

for (int i = 1; i

k; i++) {

kk = kk * 2;

}

return kk;

}

final private static double noncontracted(final int steps, final int k)

{

double res=0;

for (int m = steps; m > 0; m--) {

res = (1 + m*(-4 + 4*m))/ (8*k+2 + res);

}

int numerator =factorial(k)*factorial(k);

int denominator=factorial(2*k);

return (double) numerator*numerator/denominator/denominator*power(4*k)* 4/(4*k+1+res);

}

final private static double contracted(final int steps, final int k)

{

double res=0;

for (int m = steps-1; m > -1; m--) {

res = (-225 + m*(-960 + m*(-1504 + (-1024 - 256*m)*m)))/ ((78 + k*(32 + 64*k) + m*(96 + 32*m)) + res);

}

int numerator =factorial(k)*factorial(k);

int denominator=factorial(2*k);

return (double) numerator*numerator/denominator/denominator*power(4*k)* 4/(4*k+1+(2 + 8*k)/(13 + k* (32 + 64*k)+res));

}

final public static void main(String[] args)

{

Random generator = new Random();

long t1, t2;

long t3=0;

long t4=0;

double ratio;

int n,k;

for (int c = 0; c < 10000; c++) {

n = 3+generator.nextInt(18);

k = generator.nextInt(5);

t1 = System.currentTimeMillis();

for (int i = 0; i < 1000; i++) {

noncontracted(2*n+2,k);

}

t2 = System.currentTimeMillis();

t3= t3+t2-t1;

t1 = System.currentTimeMillis();

for (int i = 0; i < 1000; i++) {

contracted(n,k);

}

t2 = System.currentTimeMillis();

t4= t4+t2-t1;

}

ratio=(double)t3/t4;

System.out.println("Method: non-contracted, Milliseconds: " + t3);

System.out.println("Method: contracted, Milliseconds: " + t4+", Ratio: "+ratio);

}

}