计算方法实验7:实现三次样条插值算法

任务

point.txt文件中包含了21个压铁的位置信息

  1. 利用大M法计算出木条在压铁控制下的曲线,边界条件取自然边界条件;
  2. 将第10个压铁的位置移动至(0,10),计算出新的曲线,观察每个区间内的三次函数是否改变。

算法

μ i M i − 1 + 2 M i + λ i M i + 1 = d i , i = 1 , 2 , ⋯   , n − 1 \mu_{i}M_{i-1}+2M_{i}+\lambda_{i}M_{i+1}=d_{i},i=1,2,\cdots,n-1 μiMi1+2Mi+λiMi+1=di,i=1,2,,n1

其中

μ i = 1 − λ i \mu_{i}=1-\lambda_{i} μi=1λi

h i h i + h i \frac{h_{i}}{h_{i}+h_{i}} hi+hihi

d i = 6 h i + h i − 1 ( y i + 1 − y i h i − y i − y i − 1 h i − 1 ) = 6 f ( x i − 1 , x i , x i + 1 ) d_{i}=\frac{6}{h_{i}+h_{i-1}}\left({\frac{y_{i+1}-y_{i}}{h_{i}}-\frac{y_{i}-y_{i-1}}{h_{i-1}}}\right)=6f\left(x_{i-1},x_{i},x_{i+1}\right) di=hi+hi16(hiyi+1yihi1yiyi1)=6f(xi1,xi,xi+1)

给 定 M 0 , M n M_{0}, M_{n} M0,Mn的值,此时 n − 1 n-1 n1个方程组有 n − 1 n-1 n1个未知量 { M i , i = 1 , 2 , ⋯   , n − 1 } . 当 M 0 = 0 , M n = 0 \left\{M_i,i=1,\right.2,\cdots,n-1\}.当M_{0}=0,M_{n}=0 {Mi,i=1,2,,n1}.M0=0,Mn=0时,称为自然边界条件.
[ 2 λ 1 μ 2 2 λ 2 ⋱ ⋱ ⋱ μ n − 2 2 λ n − 2 μ n − 1 2 ] [ M 1 M 2 M n − 2 M n − 1 ] = [ d 1 − μ 1 M 0 d 2 ⋮ d n − 2 d n − 1 − λ n − 1 M n ] \begin{bmatrix}2&\lambda_{1}\\\mu_{2}&2&\lambda_{2}\\&\ddots&\ddots&\ddots\\&&\mu_{n-2}&2&\lambda_{n-2}\\&&&\mu_{n-1}&2\end{bmatrix}\begin{bmatrix}M_{1}\\M_{2}\\\\M_{n-2}\\\\M_{n-1}\end{bmatrix}=\begin{bmatrix}d_{1}-\mu_{1}M_{0}\\d_{2}\\\vdots\\d_{n-2}\\d_{n-1}-\lambda_{n-1}M_{n}\end{bmatrix} 2μ2λ12λ2μn22μn1λn22 M1M2Mn2Mn1 = d1μ1M0d2dn2dn1λn1Mn
S ( x ) = ( x i + 1 − x ) 3 M i + ( x − x i ) 3 M i + 1 6 h i + ( x i + 1 − x ) y i + ( x − x i ) y i + 1 h i − h i 6 [ ( x i + 1 − x ) M i + ( x − x i ) M i + 1 ] , x ∈ [ x i , x i + 1 ] \begin{aligned}S\left(x\right)=&\frac{\left(x_{i+1}-x\right)^{3}M_{i}+\left(x-x_{i}\right)^{3}M_{i+1}}{6h_{i}}+\frac{\left(x_{i+1}-x\right)y_{i}+\left(x-x_{i}\right)y_{i+1}}{h_{i}}\\&-\frac{h_{i}}{6}[(x_{i+1}-x)M_{i}+(x-x_{i})M_{i+1}],\quad x\in[x_{i},x_{i+1}]\end{aligned} S(x)=6hi(xi+1x)3Mi+(xxi)3Mi+1+hi(xi+1x)yi+(xxi)yi+16hi[(xi+1x)Mi+(xxi)Mi+1],x[xi,xi+1]

代码

#include<bits/stdc++.h>
using namespace std;

//三次样条插值
vector<long double> Spline_Interpolation(const vector<long double>& x, const vector<long double>& y);
// 列主元消去法求解线性方程组
vector<long double> Column_Elimination(vector<vector<long double>> A, vector<long double> b);

int main()
{
    ifstream file("point.txt");
    if (!file) {
        cerr << "Unable to open file point.txt";
        return 1;
    }

    vector<long double> x, y, lambda, d, h1, miu, h2;
    long double a, b;
    while (file >> a >> b)
    {
        x.push_back(a);
        y.push_back(b);
        lambda.push_back(0);
        d.push_back(0);
        h1.push_back(0);
        h2.push_back(0);
        miu.push_back(0);
    }
    
    cout << "原始数据插值结果:" << endl;
    vector<long double> M1 = Spline_Interpolation(x, y);
    vector<vector<long double>> S1(M1.size()-1, vector<long double>(4, 0));
    for(int i = 0; i < M1.size(); i++)
    {
        cout << "M1[" << i << "]:" << M1[i] << endl;
        h1[i] = x[i + 1] - x[i];
    }    
    cout << endl;
    for(int i = 0; i < M1.size() - 1; i++)
    {
        cout << "S1[" << i << "]:";
        S1[i][0] = (M1[i + 1] - M1[i]) / (6 * h1[i]);
        cout << S1[i][0] << "x^3";
        S1[i][1] = (x[i + 1] * M1[i] - x[i] * M1[i + 1]) / (2 * h1[i]);
        if(S1[i][1] >= 0)
            cout << "+" ;
        cout << S1[i][1] << "x^2";
        S1[i][2] = (3 * M1[i+1] * x[i] * x[i] - 3 * M1[i] * x[i + 1] * x[i + 1] - 6 * y[i] + 6 * y[i+1] + h1[i] * h1[i] * M1[i] - h1[i] * h1[i] * M1[i + 1]) / (6 * h1[i]);
        if(S1[i][2] >= 0)
            cout << "+" ;
        cout << S1[i][2] << "x";
        S1[i][3] = (x[i + 1] * x[i + 1] * x[i + 1] * M1[i] - x[i] * x[i] * x[i] * M1[i + 1] + 6 * x[i+1] * y[i] - 6 * x[i] * y[i+1] - h1[i] * h1[i] * M1[i] * x[i+1] + h1[i] * h1[i] * M1[i+1] * x[i]) / (6 * h1[i]);
        if(S1[i][3] >= 0)
            cout << "+" ;
        cout << S1[i][3];
        cout << endl;
    }

    //修改第十个压铁的坐标为(0,10)
    cout << endl << "修改第十个压铁的坐标为(0,10)后:" << endl;
    y[9] = 10;
    vector<long double> M2 = Spline_Interpolation(x, y);
    vector<vector<long double>> S2(M2.size()-1, vector<long double>(4, 0));
    for(int i = 0; i < M2.size(); i++)
    {
        cout << "M2[" << i << "]:" << M2[i] << endl;
        h2[i] = x[i + 1] - x[i];
    }
    cout << endl;
    for(int i = 0; i < M2.size() - 1; i++)
    {
        cout << "S2[" << i << "]:";
        S2[i][0] = (M2[i + 1] - M2[i]) / (6 * h1[i]);
        cout << S2[i][0] << "x^3";
        S2[i][1] = (x[i + 1] * M1[i] - x[i] * M2[i + 1]) / (2 * h1[i]);
        if(S2[i][1] >= 0)
            cout << "+" ;
        cout << S2[i][1] << "x^2";
        S2[i][2] = (3 * M2[i+1] * x[i] * x[i] - 3 * M2[i] * x[i + 1] * x[i + 1] - 6 * y[i] + 6 * y[i+1] + h2[i] * h2[i] * M2[i] - h2[i] * h2[i] * M2[i + 1]) / (6 * h2[i]);
        if(S2[i][2] >= 0)
            cout << "+" ;
        cout << S2[i][2] << "x";
        S2[i][3] = (x[i + 1] * x[i + 1] * x[i + 1] * M2[i] - x[i] * x[i] * x[i] * M2[i + 1] + 6 * x[i+1] * y[i] - 6 * x[i] * y[i+1] - h2[i] * h2[i] * M2[i] * x[i+1] + h2[i] * h2[i] * M2[i+1] * x[i]) / (6 * h2[i]);
        if(S2[i][3] >= 0)
            cout << "+" ;
        cout << S2[i][3];
        cout << endl;
    }
    return 0;
}

//三次样条插值
vector<long double> Spline_Interpolation(const vector<long double>& x, const vector<long double>& y) 
{
    int len = x.size();
    int n = len - 1;
    vector<long double> h(n), lambda(n), miu(n), d(n);
    for(int i = 0; i < n; i++)
        h[i] = x[i + 1] - x[i];
    for(int i = 1; i < n; i++)
    {
        lambda[i] = h[i] / (h[i] + h[i - 1]);
        miu[i] = 1 - lambda[i];
        d[i] = 6 / (h[i] + h[i - 1]) * ((y[i + 1] - y[i]) / h[i] - (y[i] - y[i - 1]) / h[i - 1]);
    }
    vector<vector<long double>> A(n - 1, vector<long double>(n - 1, 0));
    for(int i = 0; i < n - 1; i++)
    {
        A[i][i] = 2;
        if(i != 0)
            A[i][i - 1] = miu[i + 1];
        if(i != n - 2)
            A[i][i + 1] = lambda[i + 1];
    }
    vector<long double> B(n - 1, 0);
    for(int i = 0; i < n - 1; i++)
        B[i] = d[i + 1];
    vector<long double> M = Column_Elimination(A, B);
    return M;
}

// 列主元消去法求解线性方程组
vector<long double> Column_Elimination(vector<vector<long double>> A, vector<long double> b)
{
    int n = A.size();
    vector<long double> x(n + 2, 0);
    vector<vector<long double>> matrix(n, vector<long double>(n + 1, 0));

    for(int i = 0; i < n; i++)
    {
        matrix[i][n] = b[i];
        for(int j = 0; j < n; j++)
            matrix[i][j] = A[i][j];
    }
        
    for(int col = 0; col < n; col++)//找到列主元
    {
        long double maxnum = abs(matrix[col][col]);
        int maxrow = col;
        for(int row = col + 1; row < n; row++)
        {
            if(abs(matrix[row][col]) > maxnum)
            {
                maxnum = abs(matrix[row][col]);
                maxrow = row;
            }
        }
        swap(matrix[col], matrix[maxrow]);
        for(int row = col + 1; row < n; row++)
        {
            long double res = matrix[row][col] / matrix[col][col];
            for(int loc = col; loc <= n; loc++)
                matrix[row][loc] -= matrix[col][loc] * res; 
        }
    }
    for(int row = n - 1; row >= 0; row--)//回代
    {
        for(int col = row + 1; col < n; col++)
        {
            matrix[row][n] -= matrix[col][n] * matrix[row][col] / matrix[col][col];
            matrix[row][col] = 0;
        }
        matrix[row][n] /= matrix[row][row];
        matrix[row][row] = 1;
    }
    for(int i = 0; i < n; i++)
        x[i+1] = matrix[i][n];
    return x;
}
  • 32
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里澄江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值