struct Base_interp { Int n, mm, jsav, cor, dj; const Doub *xx, *yy; Base_interp(VecDoub_I &x, const Doub *y, Int m) : n(x.size()), mm(m), jsav(0), cor(0), xx(&x[0]), yy(y) { dj = MAX(1,(int)pow((Doub)n,0.25)); } Doub interp(Doub x) { Int jlo = cor ? hunt(x) : locate(x); return rawinterp(jlo,x); } Int locate(const Doub x); Int hunt(const Doub x); Doub virtual rawinterp(Int jlo, Doub x) = 0; }; Int Base_interp::locate(const Doub x) { Int ju,jm,jl; if (n < 2 || mm < 2 || mm > n) throw("locate size error"); Bool ascnd=(xx[n-1] >= xx[0]); jl=0; ju=n-1; while (ju-jl > 1) { jm = (ju+jl) >> 1; if (x >= xx[jm] == ascnd) jl=jm; else ju=jm; } cor = abs(jl-jsav) > dj ? 0 : 1; jsav = jl; return MAX(0,MIN(n-mm,jl-((mm-2)>>1))); } Int Base_interp::hunt(const Doub x) { Int jl=jsav, jm, ju, inc=1; if (n < 2 || mm < 2 || mm > n) throw("hunt size error"); Bool ascnd=(xx[n-1] >= xx[0]); if (jl < 0 || jl > n-1) { jl=0; ju=n-1; } else { if (x >= xx[jl] == ascnd) { for (;;) { ju = jl + inc; if (ju >= n-1) { ju = n-1; break;} else if (x < xx[ju] == ascnd) break; else { jl = ju; inc += inc; } } } else { ju = jl; for (;;) { jl = jl - inc; if (jl <= 0) { jl = 0; break;} else if (x >= xx[jl] == ascnd) break; else { ju = jl; inc += inc; } } } } while (ju-jl > 1) { jm = (ju+jl) >> 1; if (x >= xx[jm] == ascnd) jl=jm; else ju=jm; } cor = abs(jl-jsav) > dj ? 0 : 1; jsav = jl; return MAX(0,MIN(n-mm,jl-((mm-2)>>1))); } struct Poly_interp : Base_interp { Doub dy; Poly_interp(VecDoub_I &xv, VecDoub_I &yv, Int m) : Base_interp(xv,&yv[0],m), dy(0.) {} Doub rawinterp(Int jl, Doub x); }; Doub Poly_interp::rawinterp(Int jl, Doub x) { Int i,m,ns=0; Doub y,den,dif,dift,ho,hp,w; const Doub *xa = &xx[jl], *ya = &yy[jl]; VecDoub c(mm),d(mm); dif=abs(x-xa[0]); for (i=0;i 0.99e99) y2[0]=u[0]=0.0; else { y2[0] = -0.5; u[0]=(3.0/(xv[1]-xv[0]))*((yv[1]-yv[0])/(xv[1]-xv[0])-yp1); } for (i=1;i 0.99e99) qn=un=0.0; else { qn=0.5; un=(3.0/(xv[n-1]-xv[n-2]))*(ypn-(yv[n-1]-yv[n-2])/(xv[n-1]-xv[n-2])); } y2[n-1]=(un-qn*u[n-2])/(qn*y2[n-2]+1.0); for (k=n-2;k>=0;k--) y2[k]=y2[k]*y2[k+1]+u[k]; } Doub Spline_interp::rawinterp(Int jl, Doub x) { Int klo=jl,khi=jl+1; Doub y,h,b,a; h=xx[khi]-xx[klo]; if (h == 0.0) throw("Bad input to routine splint"); a=(xx[khi]-x)/h; b=(x-xx[klo])/h; y=a*yy[klo]+b*yy[khi]+((a*a*a-a)*y2[klo] +(b*b*b-b)*y2[khi])*(h*h)/6.0; return y; } struct BaryRat_interp : Base_interp { VecDoub w; Int d; BaryRat_interp(VecDoub_I &xv, VecDoub_I &yv, Int dd); Doub rawinterp(Int jl, Doub x); Doub interp(Doub x); }; BaryRat_interp::BaryRat_interp(VecDoub_I &xv, VecDoub_I &yv, Int dd) : Base_interp(xv,&yv[0],xv.size()), w(n), d(dd) { if (n<=d) throw("d too large for number of points in BaryRat_interp"); for (Int k=0;k= n-d ? n-d-1 : k; Doub temp = imin & 1 ? -1.0 : 1.0; Doub sum=0.0; for (Int i=imin;i<=imax;i++) { Int jmax=MIN(i+d,n-1); Doub term=1.0; for (Int j=i;j<=jmax;j++) { if (j==k) continue; term *= (xx[k]-xx[j]); } term=temp/term; temp=-temp; sum += term; } w[k]=sum; } } Doub BaryRat_interp::rawinterp(Int jl, Doub x) { Doub num=0,den=0; for (Int i=0;i