Subject: polynomial interpolation with error estimate
From: Edwin Woollett
Date: Mon, 12 Dec 2011 13:14:00 -0800
A simple transcription, using hashed arrays, of polint
from numerical recipes fortran 77, 2nd. ed, 1992.
http://www.nrbook.com/a/bookfpdf.php
This approach is based on Neville's algorithm.
/* interpolate.mac */
/* polint transcribed from fortran 77 2nd. ed.
of numerical recipes, ch. 3, p. 103.
xa and ya are hashed arrays of length n
c and d are hashed arrays of length n.
For example, if n = 3, then we are given
values of xa[j] and ya[j] for j = 1,2,3,
and create c[j] and d[j] for j = 1,2,3,
and the three data points (x,y) provided
are used to create a quadratic which goes
through the given three points, and then
the quadratic is used to estimate y(x).
polint(xa,ya,n,x) returns a list [y,dy],
where y is an interpolated value for y(x),
and dy is the estimated relative error.
*/
polint(xa,ya,n,x) :=
block ([y,dy,i,m,ns:1,den,dif,dift,ho,hp,
w,fails:false],
dif : abs(x-xa[1]),
for i thru n do
(dift : abs(x-xa[i]),
if dift < dif then
(ns : i,
dif : dift),
c[i] : ya[i],
d[i] : ya[i]),
y : ya[ns],
ns : ns - 1,
for m thru n-1 do
(for i thru n-m do
(ho : xa[i] - x,
hp : xa[i+m] - x,
w : c[i+1] - d[i],
den : ho - hp,
if den = 0.0 then
(fails:true,
print (" failure in polint "),
return()),
den : w/den,
d[i] : hp*den,
c[i] : ho*den),
if fails then return(),
if (2*ns < (n-m)) then
dy : c[ns+1]
else
(dy : d[ns],
ns : ns - 1),
y : y + dy),
remarray (c,d),
if fails then [false,false]
else [y,dy])$
/************ xpolint1 driver for polint ***************/
/* transcribed from numerical recipes example book (fortran)
2nd edition,p. 31. */
xpolint1(nn) :=
block ([ii,xv,yv,dyv ],
if nn >= 10 then
(print (" choose nn < 10 "),
return(false)),
disp (" sin(x) for 0 < x <= %pi "),
for ii thru nn do
(xx[ii] : float(ii*%pi/nn),
yy[ii] : sin(xx[ii])),
/* based on the nn points, estimate the
value of y(xv) at 10 points xv. */
/* print(" xv sin(xv) yv dyv "), */
printf(true," ~12a ~12a ~12a ~12a ~%","xv","sin(xv)","yv","dyv"),
for ii thru 10 do
( xv : float((-0.05 + ii/10)*%pi),
[yv,dyv] : polint(xx,yy,nn,xv),
/* print(" ",xv," ",sin(xv)," ",yv," ",dyv) */
printf(true," ~12e ~12e ~12e ~12e ~%",xv,sin(xv),yv,dyv)),
remarray(xx,yy),
done)$
/*
(%i1) load(interpolate);
(%o1) "c:/work2/interpolate.mac"
(%i2) xpolint1(5);
" sin(x) for 0 < x <= %pi "
xv sin(xv) yv
dyv
1.5707963E-1 1.5643447E-1 1.5518926E-1 7.8254225E-2
4.712389E-1 4.539905E-1 4.5341805E-1 1.3211752E-2
7.8539816E-1 7.0710678E-1 7.074428E-1 -5.216948E-3
1.0995574E+0 8.9100652E-1 8.9124652E-1 -3.048866E-3
1.4137167E+0 9.8768834E-1 9.8748454E-1 2.3713402E-3
1.727876E+0 9.8768834E-1 9.8748454E-1 2.3713402E-3
2.0420352E+0 8.9100652E-1 8.9124652E-1 -3.048866E-3
2.3561945E+0 7.0710678E-1 7.074428E-1 -5.216948E-3
2.6703538E+0 4.539905E-1 4.5341805E-1 1.3211752E-2
2.984513E+0 1.5643447E-1 1.5518926E-1 -5.216948E-3
(%o2) done
(%i3) xpolint1(9);
" sin(x) for 0 < x <= %pi "
xv sin(xv) yv dyv
1.5707963E-1 1.5643447E-1 1.564342E-1 4.981823E-5
4.712389E-1 4.539905E-1 4.5399055E-1 -3.279139E-6
7.8539816E-1 7.0710678E-1 7.0710677E-1 5.9718307E-7
1.0995574E+0 8.9100652E-1 8.9100653E-1 -1.604347E-7
1.4137167E+0 9.8768834E-1 9.8768834E-1 3.6628832E-8
1.727876E+0 9.8768834E-1 9.8768834E-1 3.6628832E-8
2.0420352E+0 8.9100652E-1 8.9100653E-1 -1.604347E-7
2.3561945E+0 7.0710678E-1 7.0710677E-1 5.9718307E-7
2.6703538E+0 4.539905E-1 4.5399055E-1 -3.279139E-6
2.984513E+0 1.5643447E-1 1.564342E-1 -2.969298E-6
(%o3) done
*/
Original fortran77 code:
SUBROUTINE polint(xa,ya,n,x,y,dy)
INTEGER n,NMAX
REAL dy,x,y,xa(n),ya(n)
PARAMETER (NMAX=10)
INTEGER i,m,ns
REAL den,dif,dift,ho,hp,w,c(NMAX),d(NMAX)
ns=1
dif=abs(x-xa(1))
do 11 i=1,n
dift=abs(x-xa(i))
if (dift.lt.dif) then
ns=i
dif=dift
endif
c(i)=ya(i)
d(i)=ya(i)
11 continue
y=ya(ns)
ns=ns-1
do 13 m=1,n-1
do 12 i=1,n-m
ho=xa(i)-x
hp=xa(i+m)-x
w=c(i+1)-d(i)
den=ho-hp
if(den.eq.0.)pause 'failure in polint'
den=w/den
d(i)=hp*den
c(i)=ho*den
12 continue
if (2*ns.lt.n-m)then
dy=c(ns+1)
else
dy=d(ns)
ns=ns-1
endif
y=y+dy
13 continue
return
END
---------------------------------
Ted Woollett