In this worksheet we use rational polynomials to approximate functions

1. Approximation with Rational Functions

For example, let us consider the function sin(x).

> restart;

> n := 3: # degree numerator

> m := 3: # degree denominator

> N := n+m: # number of terms in Maclaurin series

We start with a Maclaurin series:

> ms := taylor(sin(x),x=0,N+1);

ms := series(1*x-1/6*x^3+1/120*x^5+O(x^7),x,7)

> pms := convert(ms,polynom);

pms := x-1/6*x^3+1/120*x^5

> q := (sum(a['i']*x^'i','i'=0..n))/(1 + sum(b['i']*x^'i','i'=1..m));

q := (a[0]+a[1]*x+a[2]*x^2+a[3]*x^3)/(1+b[1]*x+b[2]...

> err := pms*denom(q) - numer(q);

err := (x-1/6*x^3+1/120*x^5)*(1+b[1]*x+b[2]*x^2+b[3...

> eqs := {}:

> for i from 0 to N do

> eqs := {op(eqs),coeff(err,x,i) = 0};

> end do:

> eqs;

{-a[0] = 0, 1-a[1] = 0, b[1]-a[2] = 0, b[2]-1/6-a[3...

> vars := {seq(a[k],k=0..n),seq(b[l],l=1..m)};

vars := {a[0], a[2], a[3], a[1], b[1], b[2], b[3]}

> sols := solve(eqs,vars);

sols := {a[0] = 0, a[3] = -7/60, b[2] = 1/20, b[3] ...

> assign(sols);

> q;

(x-7/60*x^3)/(1+1/20*x^2)

Maple has a built-in function to construct Pade approximations:

> r4 := numapprox[pade](sin(x),x,[n,m]);

r4 := (x-7/60*x^3)/(1+1/20*x^2)

We see that the error of the rational approximation is less than that of the Maclaurin series:

> plot([sin(x),r4,pms],x=-Pi..Pi);

[Maple Plot]

2. Continued Fractions

To obtain a form of the approximation that is efficient to evaluate, we use continued fractions.

> r4;

(x-7/60*x^3)/(1+1/20*x^2)

> codegen[cost](r4);

2*additions+5*multiplications+divisions

> cr4 := convert(r4,`confrac`,x);

cr4 := -7/3*x+200/3/(x+20/x)

> codegen[cost](cr4);

2*additions+multiplications+2*divisions

Thus we traded in 4 multiplications for one extra division.

We obtain the continued fraction representation by repeated polynomial division:

> a := numer(r4);

a := -x*(-60+7*x^2)

> b := denom(r4);

b := 60+3*x^2

> rest1 := rem(a,b,x,'quot1');

rest1 := 200*x

> quot1;

-7/3*x

Sanity check:

> a = expand(b*quot1 + rest1);

-x*(-60+7*x^2) = 60*x-7*x^3

Thus we can write the quotient as

> quot1 + rest1/b;

-7/3*x+200*x/(60+3*x^2)

Because deg(rest) < deg(b), we work with the equivalent 1/(b/rest1).

> rest2 := rem(b,rest1,x,'quot2');

rest2 := 60

Sanity check:

> b = expand(rest1*quot2 + rest2);

60+3*x^2 = 60+3*x^2

Thus we have the expression

> fr4 := quot1 + 1/(quot2 + rest2/rest1);

fr4 := -7/3*x+1/(3/200*x+3/10/x)

The expression we obtained is equivalent with what Maple gave us:

> normal(fr4 - cr4);

0

> codegen[cost](fr4);

2*additions+2*multiplications+2*divisions

We can save one multiplication by multiplying the quotient in the second term of fr4 by 200/3

> dd := op([2,1],fr4)*200/3;

dd := x+20/x

> nfr4 := op(1,fr4) + (200/3)/dd;

nfr4 := -7/3*x+200/3/(x+20/x)

> codegen[cost](nfr4);

2*additions+multiplications+2*divisions