【数值计算方法(黄明游)】函数插值与曲线拟合(一):Lagrange插值【理论到程序】

2024-07-30 10:44:46 浏览数 (2)

一、近似表达方式

  插值、拟合和投影都是常用的近似表达方式,用于对数据或函数进行估计、预测或表示。

1. 插值(Interpolation)

  指通过已知数据点之间的插值方法,来估计或推算出在这些数据点之间的数值。插值可以用于构建平滑的曲线或曲面,以便在数据点之间进行预测或补充缺失的数据。

2. 拟合(Fitting)

  指通过选择合适的函数形式和参数,将一个数学模型与已知数据点拟合得最好的过程。拟合的目标是找到一个函数,使其在数据点附近的值与实际观测值尽可能接近。拟合可以用于数据分析、曲线拟合、回归分析等领域。

3. 投影(Projection)

  指将一个向量或一组向量映射到另一个向量空间或子空间上的过程。在线性代数中,投影可以用来找到一个向量在另一个向量或向量空间上的投影或投影分量。投影可以用于降维、数据压缩、特征提取等领域,以及计算机图形学中的投影变换。

二、Lagrange插值

1. 天书

2. 人话

   Lagrange插值是一种用于通过已知数据点构造一个多项式函数的方法,基于拉格朗日插值多项式的原理(该多项式通过每个数据点并满足相应的条件),拉格朗日插值可用于估计数据点之间的值,而不仅仅是在给定数据点上进行插值。

拉格朗日插值方法
  1. 拉格朗日基函数: 对于给定的插值节点
x_0, x_1, ldots, x_n

,拉格朗日插值使用如下的拉格朗日基函数:

L_i(x) = prod_{j=0, jneq i}^{n} frac{x - x_j}{x_i - x_j}
  1. 插值条件: 拉格朗日插值要求插值多项式满足插值条件:对所有
i

P(x_i) = y_i
  1. 插值多项式: 构造插值多项式为:
P(x) = sum_{i=0}^{n} y_i L_i(x)

  通过这种方法,可以在给定的数据点上获得一个平滑的插值函数,使得在这些数据点之间的任何位置上都可以估计函数的值。Lagrange插值在数据点较少或数据点之间存在较大间隔时可能会出现一些问题,例如插值多项式可能会产生振荡现象,这被称为Runge现象

a. 线性插值(n=1)
基本思想
  1. 插值基函数: 在线性插值中,通常使用线性插值基函数。这些基函数是线性的,通常是一次多项式。在一维线性插值中,最简单的基函数是
1

x

  1. 插值条件: 对于给定的插值节点
x_0, x_1

和对应的函数值

y_0, y_1

,线性插值要求插值多项式满足插值条件:

P(x_0) = y_0

P(x_1) = y_1

  1. 构造插值多项式: 构造线性插值多项式为:
P(x) = y_0 frac{(x - x_1)}{(x_0 - x_1)} y_1 frac{(x - x_0)}{(x_1 - x_0)}
线性插值与线性方程组

  线性插值的理论基础是线性方程组:通过对插值条件的线性化,我们可以得到一个线性方程组,解这个方程组即可得到插值多项式的系数,进而构造出插值多项式。

b. 抛物插值(n=2)

  抛物插值是一种二次插值方法,它使用二次插值基函数构造插值多项式。抛物插值的基本思想是使用二次多项式来逼近一组给定的插值点。

基本思想
  1. 插值基函数: 插值基函数是二次多项式,即
(x - x_0)(x - x_1)

(x - x_1)(x - x_2)

(x - x_2)(x - x_0)

这样的形式。

  1. 插值条件: 对于给定的插值节点
x_0, x_1, x_2

和对应的函数值

y_0, y_1, y_2

,抛物插值要求插值多项式满足插值条件:

P(x_0) = y_0

P(x_1) = y_1

P(x_2) = y_2

  1. 构造插值多项式: 构造二次插值多项式为:
P(x) = y_0 frac{(x - x_1)(x - x_2)}{(x_0 - x_1)(x_0 - x_2)} y_1 frac{(x - x_0)(x - x_2)}{(x_1 - x_0)(x_1 - x_2)} y_2 frac{(x - x_0)(x - x_1)}{(x_2 - x_0)(x_2 - x_1)}
优点和局限性
  • 优点:
    • 相对于线性插值,抛物插值对曲线的弯曲更为灵活,更能逼近一些非线性的数据分布。
    • 二次插值基函数相对简单,计算相对容易。
  • 局限性:
    • 抛物插值要求插值节点的个数是三个,因此只能处理有三个插值点的情况。
    • 对于一些数据分布不规则或存在噪声的情况,抛物插值可能会过度拟合数据,导致插值结果不稳定。
应用场景

  抛物插值通常适用于对于较小区间内的数据进行插值的情况,例如在某一局部区域内,数据点趋势呈现抛物线状。在这种情况下,抛物插值可以提供较好的拟合效果。然而,在数据分布较为复杂或需要考虑更多插值点的情况下,可能需要考虑更高次数的插值方法或其他插值技术。

c. n次插值
n

次插值是一种一般化的插值方法,它使用

n

次多项式来逼近给定的插值点。在

n

次插值中,插值多项式的次数是

n

,这意味着需要

n 1

个互异的插值点来确定插值多项式。以下是关于

n

次插值的一些基本概念:

基本思想
  1. 插值基函数:
n

次插值中,通常使用

n 1

个插值基函数。这些基函数是

n

次多项式,可以选择为拉格朗日基函数或其他基函数形式。

  1. 插值条件: 对于给定的
n 1

个插值节点

x_0, x_1, ldots, x_n

和对应的函数值

y_0, y_1, ldots, y_n

n

次插值要求插值多项式满足插值条件:

P(x_i) = y_i

对所有

i = 0, 1, ldots, n

  1. 构造插值多项式: 构造
n

次插值多项式为:

P(x) = sum_{i=0}^{n} y_i L_i(x)

其中

L_i(x)

是插值基函数。

插值基函数的选择
  1. 拉格朗日基函数:
n

次插值中,拉格朗日基函数是常用的一种选择。每个基函数

L_i(x)

具有以下形式:

L_i(x) = prod_{j=0, jneq i}^{n} frac{x - x_j}{x_i - x_j}
  1. 其他基函数: 除了拉格朗日基函数外,还可以选择其他形式的插值基函数,例如牛顿基函数等。
优点和和局限性
  • 优点:
    n

    次插值具有很高的灵活性,可以逼近复杂的数据分布。

    • 适用于一般性的插值问题,可以处理较多的插值点。
  • 限制:
    • 随着
    n

    的增加,插值多项式的次数增加,计算和存储开销也增加。

    • 对于一些高次插值问题,可能会受到龙格现象(Runge’s phenomenon)的影响,导致插值结果不稳定。

3. python实现

代码语言:javascript复制
import numpy as np


# 定义Lagrange插值函数
def lagrange_interpolation(x, y, xi):
    n = len(x)
    yi = 0.0

    for i in range(n):
        # 计算拉格朗日插值多项式的每一项
        term = y[i]
        for j in range(n):
            if j != i:
                term *= (xi - x[j]) / (x[i] - x[j])
        yi  = term

    return yi


# 示例数据点
x = np.array([0.32, 0.34, 0.36])
y = np.array([0.314567, 0.333487, 0.352274])

# 要进行插值的点
xi = 0.3367

# 进行插值
yi = lagrange_interpolation(x, y, xi)

print("插值结果:", yi)
print("真实结果:", np.sin(xi))

输出:

代码语言:javascript复制
插值结果: 0.3303743620374999
真实结果: 0.330374191555628

4. C语言实现

代码语言:javascript复制
#include <stdio.h>

// 计算Lagrange插值多项式的值
double lagrange_interpolation(double x[], double y[], int n, double xi) {
    double yi = 0.0;

    for (int i = 0; i < n; i  ) {
        double term = y[i];
        for (int j = 0; j < n; j  ) {
            if (j != i) {
                term *= (xi - x[j]) / (x[i] - x[j]);
            }
        }
        yi  = term;
    }

    return yi;
}

int main() {
    // 示例数据点

    double x[] = {0.32, 0.34, 0.36};
    double y[] = {0.314567, 0.333487, 0.352274};

    // 要进行插值的点
    double xi = 0.3367;

    // 数据点的个数
    int n = sizeof(x) / sizeof(x[0]);

    // 进行插值
    double yi = lagrange_interpolation(x, y, n, xi);

    printf("插值结果:%fn", yi);

    return 0;
}

输出:

代码语言:javascript复制
插值结果:0.330374

0 人点赞