假设只有两个插值点: x 0 , x 1 ; y 0 , y 1 x_0,x_1;y_0,y_1 x0,x1;y0,y1,求 P 1 ( x ) = a 0 + a 1 x P_1(x)=a_0+a_1x P1(x)=a0+a1x使得 P 1 ( x 0 ) = y 0 , P 1 ( x 1 ) = y 1 P_1(x_0)=y_0,P_1(x_1)=y_1 P1(x0)=y0,P1(x1)=y1,由此可以得到 P 1 ( x ) = y 0 + y 1 − y 0 x 1 − x 0 ( x − x 0 ) = x − x 1 x 0 − x 1 y 0 + x − x 0 x 1 − x 0 y 1 = ∑ i = 0 1 l i y i \begin{align} P_1(x)&=y_0+\frac{y_1-y_0}{x_1-x_0}(x-x_0)\\ &=\frac{x-x_1}{x_0-x_1}y_0+\frac{x-x_0}{x_1-x_0}y_1\\ &=\sum_{i=0}^1l_iy_i\\ \end{align} P1(x)=y0+x1−x0y1−y0(x−x0)=x0−x1x−x1y0+x1−x0x−x0y1=i=0∑1liyi
这是对于只有两个插值点的情况,现在对其拓展到任意个插值点。
对于给出的n个插值坐标: x 0 , x 1 ⋯ x n ; y 0 , y 1 ⋯ y n x_0,x_1\cdots x_n;y_0,y_1\cdots y_n x0,x1⋯xn;y0,y1⋯yn,构造插值函数 P n ( x ) = ∑ i = 0 n l i ( x ) y i P_n(x)=\sum_{i=0}^nl_i(x)y_i Pn(x)=∑i=0nli(x)yi,显然 P n ( x i ) = y i P_n(x_i)=y_i Pn(xi)=yi,所以有 { l i ( x i ) = 1 l i ( x j ) = 0 ( i ≠ j ) \begin{cases} l_i(x_i)=1\\ l_i(x_j)=0(i\neq j) \end{cases} {li(xi)=1li(xj)=0(i=j)
因此构造出 l i ( x ) = ∏ j = 0 , j ≠ i n x − x j x i − x j l_i(x)=\prod_{j=0,j\neq i}^n\frac{x-x_j}{x_i-x_j} li(x)=j=0,j=i∏nxi−xjx−xj
代入原式,得到 L n ( x ) = ∑ i = 0 n l i ( x ) y i L_n(x)=\sum_{i=0}^nl_i(x)y_i Ln(x)=i=0∑nli(x)yi
对应的 l i ( x ) l_i(x) li(x)被称为拉格朗日插值基函数。
//拉格朗日插值法
#include
#include
//拉格朗日插值法,输入插值点坐标、需要求值的x和插值点数n
double Lagrange(double *xi,double *yi,double x,int n)
{
double Ln = 0;
for (int i = 0; i < n;i++)
{
double li = 1.0;
for (int j = 0; j < n;j++)
{
if(i!=j)
{
li*=((x-xi[j])/(xi[i]-xi[j]));
}
}
Ln+=yi[i]*li;
}
return Ln;
}
double fx(double x)
{
return sqrt(x + 3);
}
int main()
{
int n;
std::cout << "输入插值点数:";
std::cin>>n;
double *x = new double[n];
double *y = new double[n];
double error[3]={0.0f,0.0f,0.0f};//误差评价
double a = 3, b = 10;//插值区间
for(int i=0;ierror[0])
{
error[0] = fabs(y_temp-y_temp2);
//std::cout<
与直接的多项式插值法结果比较,其速度更快,在阶数相同时保持一致的误差,并且随着插值点数的增加,误差还可以进一步减小,对于测试函数 x + 3 \sqrt{x+3} x+3其龙格现象没那么明显。
为了评估插值函数在计算某个x时的误差,计 R n ( x ) = f ( x ) − L n ( x ) R_n(x)=f(x)-L_n(x) Rn(x)=f(x)−Ln(x),可以得到 R n ( x ) = f ( n + 1 ) ( ξ x ) ( n + 1 ) ! ∏ i = 0 n ( x − x i ) ( min ( x 0 , x 1 , ⋯ x n ) ≤ ξ ≤ max ( x 0 , x 1 , ⋯ x n ) ) R_n(x)=\frac{f^{(n+1)(\xi _x)}}{(n+1)!}\prod_{i=0}^n{(x-x_i)}(\min{(x_0,x_1,\cdots x_n)\le \xi \le \max{(x_0,x_1,\cdots x_n)}}) Rn(x)=(n+1)!f(n+1)(ξx)∏i=0n(x−xi)(min(x0,x1,⋯xn)≤ξ≤max(x0,x1,⋯xn)),但是用插值函数的时候,意味着原函数在特定的平台较难计算,因此为了方便估计这个误差,使用事后估计法:设 L n ( x ) L_n(x) Ln(x)为 f ( x ) f(x) f(x)以 x 0 , x 1 , ⋯ x n x_0,x_1,\cdots x_n x0,x1,⋯xn为节点的插值多项式,另外取一个节点 x n + 1 x_{n+1} xn+1,记 L n ( 1 ) ( x ) L_n^{(1)}(x) Ln(1)(x)为 f ( x ) f(x) f(x)以 x 1 , x 2 ⋯ x n , x n + 1 x_1,x_2\cdots x_n,x_{n+1} x1,x2⋯xn,xn+1为节点的插值多项式,则有
f ( x ) − L n ( x ) = f ( n + 1 ) ( ξ 1 ) ( n + 1 ) ! ∏ i = 0 n ( x − x i ) f(x)-L_n(x)=\frac{f^{(n+1)(\xi _1)}}{(n+1)!}\prod_{i=0}^n{(x-x_i)} f(x)−Ln(x)=(n+1)!f(n+1)(ξ1)i=0∏n(x−xi)
f ( x ) − L n ( 1 ) ( x ) = f ( n + 1 ) ( ξ 2 ) ( n + 1 ) ! ∏ i = 1 n + 1 ( x − x i ) f(x)-L^{(1)}_n(x)=\frac{f^{(n+1)(\xi _2)}}{(n+1)!}\prod_{i=1}^{n+1}{(x-x_i)} f(x)−Ln(1)(x)=(n+1)!f(n+1)(ξ2)i=1∏n+1(x−xi)
由于 f ( n + 1 ) ( x ) f^{(n+1)}(x) f(n+1)(x)在插值区间上变化不大,因此可以认为 f ( x ) − L n ( x ) f ( x ) − L n ( 1 ) ( x ) ≈ x − x 0 x − x n + 1 \frac{f(x)-L_n(x)}{f(x)-L^{(1)}_n(x)}\approx \frac{x-x_0}{x-x_{n+1}} f(x)−Ln(1)(x)f(x)−Ln(x)≈x−xn+1x−x0
转化一下可以得到
f ( x ) − L n ( x ) ≈ x − x 0 x n + 1 − x 0 ( L n ( x ) − L n ( 1 ) ( x ) ) f(x)-L_n(x)\approx \frac{x-x_0}{x_{n+1}-x_0}(L_n(x)-L^{(1)}_n(x)) f(x)−Ln(x)≈xn+1−x0x−x0(Ln(x)−Ln(1)(x))
这个估计误差的方法就被称为时候估计法,当需要计算某次插值的计算误差时,就可以直接使用该方法进行误差估计。