#include "stdafx.h"
#include <math.h>
// 插值
double
PI()
{
return
(
atan
(1.)*4);
}
// x | pi/6 pi/4 pi/3
//------------------------------------
// y | 1/2 sqrt(2)/2 sqrt(3)/2
void
LagrangeInterpolation_Order1()
{
printf
(
"Lagrange 插值(1階): \n"
);
int
n = 1;
double
x[2],y[2];
double
phi,x0,y0,l;
int
k,i;
double
err;
x[0] = PI()/6; y[0] = 0.5;
x[1] = PI()/4; y[1] =
sqrt
(2.)/2.;
x0 = PI()*5/18;
y0 =
sin
(x0);
// 真值
PS(&y0,1,
"sin(5*pi/18)"
);
phi = 0.;
for
(k=0;k<=n;k++)
{
l = 1.;
for
(i=0;i<=n;i++)
{
if
(i!=k)
l *= ( (x0-x[i])/(x[k]-x[i]) );
}
phi += l*y[k];
}
PS(&phi,n,
"phi"
);
err =
sin
(x0)*(x0-x[0])*(x0-x[1])/2.;
err =
abs
(err);
printf
(
"誤差 R1(x0) = %f\n"
,err);
}
// x | pi/6 pi/4 pi/3
//------------------------------------
// y | 1/2 sqrt(2)/2 sqrt(3)/2
void
LagrangeInterpolation_Order2()
{
printf
(
"Lagrange 插值(2階): \n"
);
int
n = 2;
double
x[3],y[3];
double
phi,x0,y0,l;
int
k,i;
double
err;
x[0] = PI()/6; y[0] = 0.5;
x[1] = PI()/4; y[1] =
sqrt
(2.)/2.;
x[2] = PI()/3; y[2] =
sqrt
(3.)/2.;
x0 = PI()*5/18;
y0 =
sin
(x0);
// 真值
PS(&y0,1,
"sin(5*pi/18)"
);
phi = 0.;
for
(k=0;k<=n;k++)
{
l = 1.;
for
(i=0;i<=n;i++)
{
if
(i!=k)
l *= ( (x0-x[i])/(x[k]-x[i]) );
}
phi += l*y[k];
}
PS(&phi,1,
"phi"
);
err = 1;
for
(i=0;i<=n;i++) {
err *= ((x0-x[i])/(i+1));
}
err *=
cos
(PI()/6);
err =
abs
(err);
printf
(
"誤差 R2(x0) = %f\n"
,err);
}
// x | 0 pi/6 pi/4 pi/3 pi/2
//-----------------------------------------------------
// y | 0 1/2 sqrt(2)/2 sqrt(3)/2 1
void
NewtonInterpolation()
{
printf
(
"四次牛頓插值多項式(Page77):\n"
);
double
f[5][5];
int
n = 4;
int
i,j;
double
pi = PI();
double
x[5] = {0,pi/6,pi/4,pi/3,pi/2};
double
N;
double
tmp;
double
x0 = pi*5/18;
for
(i=0;i<=n;i++)
{
for
(j=0;j<=n;j++) f[i][j]=0.;
}
for
(i = 0; i <= n; i++) {
f[i][0] =
sin
(x[i]);
// x[i] /= pi;
// x[i] *= 180;
}
// 計算差商
for
(j=1;j<=n;j++)
{
// 列,階數
for
(i=0;i<=n-j;i++)
{
f[i][j] = f[i][j-1] - f[i+1][j-1];
f[i][j] /= (x[i]-x[i+j]);
}
}
printf
(
"%d階差商:\n"
,n);
for
(i=0;i<=n;i++)
{
for
(j=0;j<=n-i;j++)
printf
(
"%.9f\t"
,f[i][j]);
printf
(
"\n"
);
}
// 求值
N = 0;
for
(i=0;i<=n;i++)
{
tmp = 1.;
for
(j=0;j<i;j++)
tmp = tmp * (x0-x[j]);
N += tmp*f[0][i];
}
PS(&N,1,
"N4(5*pi/18)"
);
}
void
NewtonInterpolation_example4()
{
printf
(
"牛頓向前向後插值(節點等間隔): Page81"
);
double
x[4] = {0.4,0.5,0.6,0.7};
double
f[4][4];
int
i,j;
int
n=3;
double
x0 = 0.65;
double
t,h=0.1;
double
N,tmp;
for
(i=0;i<=n;i++)
{
for
(j=0;j<=n;j++) f[i][j]=0.;
}
for
(i = 0; i <= n; i++) {
f[i][0] =
sin
(x[i]);
}
// 計算差分
for
(j=1;j<=n;j++)
{
// 列,階數
for
(i=0;i<=n-j;i++)
{
f[i][j] = f[i+1][j-1]-f[i][j-1];
// f[i][j] /= (x[i]-x[i+j]);
}
}
printf
(
"%d階差商:\n"
,n);
for
(i=0;i<=n;i++)
{
for
(j=0;j<=n-i;j++)
printf
(
"%.5f\t"
,f[i][j]);
printf
(
"\n"
);
}
// 前向差分
t = (x0-x[0])/h;
N = 0.;
for
(i = 0; i <= n; i++) {
tmp = 1.;
for
(j=0;j<i;j++) {
tmp = tmp*(t-j)/(j+1);
}
N+=tmp*f[0][i];
}
printf
(
"向前插值近似:\n"
);
PS(&N,1,
"sin(0.65)"
);
// 三次向前插值誤差
double
R3 = 1.;
for
(i=0;i<=n;i++) {
R3 *= h*(t-i)/(i+1);
}
R3 =
abs
(R3);
printf
(
"R3=%.3ef\n"
,R3);
// 後向差分近似
t = (x0-x[n])/h;
N = 0.;
for
(i = 0; i <= n; i++) {
tmp = 1.;
for
(j=0;j<i;j++) {
tmp = tmp*(t+j)/(j+1);
}
N+=tmp*f[n-i][i];
}
printf
(
"向後插值近似:\n"
);
PS(&N,1,
"sin(0.65)"
);
printf
(
"真值sin(0.65)=%f\n"
,
sin
(x0));
// 向後插值近似(2次)
n--;
t = (x0-x[n])/h;
N = 0.;
for
(i = 0; i <= n; i++) {
tmp = 1.;
for
(j=0;j<i;j++) {
tmp = tmp*(t+j)/(j+1);
}
N+=tmp*f[n-i][i];
}
printf
(
"向後插值近似(2次):\n"
);
PS(&N,1,
"N2"
);
// 二次向後插值誤差
double
R2 = 1.;
for
(i=0;i<=n;i++) {
R2 *= h*(t+i)/(i+1);
}
R2 =
abs
(R2);
printf
(
"R3=%.3ef\n"
,R2);
}
// x | 0.4 0.5 0.7 0.8
//---------------------------------
// y | lnx
//---------------------------------
// y'| 1/x
void
HermiteInterpolation()
{
printf
(
"埃爾米特插值:\n"
);
double
x[4] = {0.4,0.5,0.7,0.8};
int
n = 3;
int
orderN = 2*n+1;
double
xp = 0.6;
double
tmp;
double
y[4],dy[4];
int
i,j,k;
double
H[4],h[4];
// 插值 H(0.6)
// 賦值
for
(i=0;i<=n;i++) {
y[i] =
log
(x[i]);
dy[i]= 1./x[i];
}
for
(i=0;i<=n;i++)
// hi,Hi, i=0,1,...,n,多項式個數
{
h[i] = H[i] = 1.;
for
(j=0;j<=n;j++)
// j=0,1,...,n,因式個數
{
if
(j==i)
// i==j時,Hi,hi子式不同,其餘情況子式相同
{
tmp = 1.;
for
(k=0;k<=n;k++)
{
if
(k!=j)
tmp += 2*(xp-x[i])/(x[k]-x[j]);
}
h[i] *= tmp;
H[i] *= (xp-x[i]);
}
else
{
tmp = (xp-x[j])/(x[i]-x[j]);
tmp = tmp*tmp;
h[i] *= tmp;
H[i] *= tmp;
}
}
}
PS(h,n+1,
"h"
);
PS(H,n+1,
"H"
);
// 插值近似
tmp = 0.;
for
(i=0;i<=n;i++)
tmp += ((h[i]*y[i])+(H[i]*dy[i]));
printf
(
"插值ln(0.6)=%f\n"
,tmp);
printf
(
"真值ln(0.6)=%f\n"
,
log
(0.6));
}
// x | xi = -1 + i/5
//---------------------------------
// y | 1/(1+25x^2)
//---------------------------------
void
LagrangeInterpolation_Order10()
{
printf
(
"龍格現象: Page86\n"
);
int
n =10;
double
x[11],y[11];
double
phi[11],x0[11],y0[11],l;
int
k,i,j;
double
err[11];
// 插值節點
for
(i=0;i<=n;i++) {
x[i] = -1 + 2.*i/10;
y[i] = 1+25*x[i]*x[i];
y[i] = 1./y[i];
}
// 估計節點,真實值
for
(i=0;i<=n;i++) {
x0[i] = 0.1*i;
y0[i] = 1+25*x0[i]*x0[i];
y0[i] = 1./y0[i];
}
PS(x0,n+1,
"xi"
);
PS(y0,n+1,
"f(xi)"
);
// 計算插值點
for
(j=0;j<=n;j++)
// 插值節點
{
phi[j] = 0.;
for
(k=0;k<=n;k++)
// 子多項式個數
{
l = 1.;
for
(i=0;i<=n;i++)
// 因式個數
{
if
(i!=k)
l *= ( (x0[j]-x[i])/(x[k]-x[i]) );
}
phi[j] += l*y[k];
}
}
PS(phi,n+1,
"phi10(xi)"
);
// 誤差
for
(i=0;i<=n;i++) err[i] =
abs
(y0[i]-phi[i]);
PS(err,n+1,
"error"
);
}
// 插值多項式次數通常<=7
// 節點比較多時,採用分段插值算法
// 分段:線性,拋物線,連續且經過插值點
// 分段:埃爾米特,同時滿足導數相等
void
FenDuanLinearInterpolation()
{
printf
(
"分段線性插值:\n"
);
int
n = 2;
int
i;
double
l[3];
double
x[3] = {0,1,2};
double
y[3] = {0,6,4};
double
x1,f;
x1 = 1.56789;
for
(i=1;i<=n;i++)
//x1在區間x[i-1]~x[i]
{
if
(x1>=x[i-1]&&x1<x[i])
{
l[i-1] = (x1-x[i])/(x[i-1]-x[i]);
l[i] = (x1-x[i-1])/(x[i]-x[i-1]);
}
else
l[i] = 0.;
}
f = 0.;
for
(i=0;i<=n;i++)
f+=l[i]*y[i];
PS(&f,1,
"f"
);
}
// cubic spline interpolation
// 三次樣條插值
//-----------------------------------------
// i | 0 1 2 3 4 |
//-----------------------------------------
// x | -3 -1 0 3 4 |
//-----------------------------------------
// y | 7 11 26 56 29 |
//-----------------------------------------
// 第二邊值條件: x0, xn處S(x)二階導數爲0.
void
CubicSplineInterpolation()
{
printf
(
"三次樣條插值:\n"
);
double
x[5] = {-3,-1,0,3,4};
double
y[5] = {7,11,26,56,29};
int
n = 4;
double
M[5];
// 四個區間
int
i,j,k;
double
a[3][3];
double
d[3];
double
xx[3],yy[3];
double
T0,T1,T2;
// T0=x(i)-x(i-1),T1=x(i+1)-x(i),T2=x(i+1)-x(i-1);
double
dy0,dy1;
for
(i=0;i<n-1;i++)
d[i] = 0.;
for
(i=0;i<=n;i++)
M[i] = 0.;
for
(i=0;i<n-1;i++) {
for
(j=0;j<n-1;j++) {
a[i][j] = 0.;
}
}
// 係數
for
(i=1;i<=n-1;i++)
// i = 1,2,...,n-1
{
for
(j=0;j<n-1;j++)
{
k = i-1;
T0= x[i]-x[i-1];
T1=x[i+1]-x[i];
T2=x[i+1]-x[i-1];
// T0+T1
if
(k==j)
a[k][j] = 2.;
else
if
(j==k+1)
// lamda = 1-mu
a[k][j] = T1/T2;
else
if
(j==k-1)
// mu
a[k][j] = T0/T2;
else
a[k][j] = 0.;
}
}
printf
(
"a=\n"
);
for
(i = 0; i < n-1; i++)
{
for
(j = 0; j < n-1; j++)
printf
(
"%f\t"
,a[i][j]);
printf
(
"\n"
);
}
// 常數
for
(i=1;i<=n-1;i++) {
k = i-1;
T0= x[i]-x[i-1];
T1=x[i+1]-x[i];
T2=x[i+1]-x[i-1];
// T0+T1
dy0 = (y[i]-y[i-1])/T0;
dy1 = (y[i+1]-y[i])/T1;
// d[k] = 6.*((y[i+1]-y[i])/T1-(y[i]-y[i-1])/T0)/T2;
d[k] = 6.*(dy1-dy0)/T2;
// 二階導數
}
PS(d,n-1,
"d"
);
// 求解,追趕法II
// 追
double
p[3];
double
q[2];
int
nn = n-1;
p[0] = a[0][0];
q[0] = a[0][1]/p[0];
for
(i = 1; i < nn; i++)
{
p[i] = a[i][i] - a[i][i-1]*q[i-1];
if
(i<nn-1) q[i] = a[i][i+1]/p[i];
}
PS(p,nn,
"p"
);PS(q,nn-1,
"q"
);
// 趕
for
(i=0;i<nn;i++)
{
yy[i] = d[i];
if
(i>0) yy[i] -= a[i][i-1]*yy[i-1];
yy[i] /= p[i];
}
for
(i=nn-1;i>=0;i--) {
xx[i] = yy[i];
if
(i<nn-1) xx[i]-=q[i]*xx[i+1];
}
PS(yy,nn,
"y"
);PS(xx,nn,
"x"
);
for
(i=1;i<n;i++) {
M[i] = xx[i-1];
}
PS(M,n+1,
"M"
);
// 求S(1)
double
x0 = 1;
double
S = 0.;
for
(i=1;i<=n;i++) {
if
(x0>=x[i-1]&&x0<x[i])
{
T0= x[i]-x[i-1];
// T1=x[i+1]-x[i];
// T2=x[i+1]-x[i-1]; // T0+T1
S = (x[i]-x0)*(x[i]-x0)*(x[i]-x0)*M[i-1]/6/T0
+ (x0-x[i-1])*(x0-x[i-1])*(x0-x[i-1])*M[i]/6/T0
+ (x[i]-x0)/T0*(y[i-1]-M[i-1]/6*T0*T0)
+ (x0-x[i-1])/T0*(y[i]-M[i]/6*T0*T0);
}
}
PS(&S,1,
"S"
);
}