首页 > 代码库 > 三次样条插值

三次样条插值

条件
(1)输入$x_{i},y_{i}=f(x_{i}),0\leq i\leq n$
(2)要求拟合的曲线$S(x)$满足:对于任意的$1\leq i\leq n-1$,在$x_{i}$处一阶二阶导数连续,$S(x)$ 也连续,且$S^{‘}(x_{0})=f^{‘}(x_{0})$,$S^{‘}(x_{n})=f^{‘}(x_{n})$

求解过程
设$S_{x_{j}}^{‘‘}=M_{j}$。对于区间$[x_{j},x_{j+1}]$,$S(x)$是$[x_{j},x_{j+1}]$上的线性函数,所以设$S^{‘‘}=M_{j}\frac{x_{j+1}-x}{h_{j}}+M_{j+1}\frac{x-x_{j}}{h_{j}}$,$h_{j}=x_{j+1}-x_{j}$。对$S^{‘‘}$两次积分,并利用$S(x_{j})=y_{j},S(x_{y+1})=y_{j+1}$,得到:
$S(x)=M_{j}\frac{(x_{j+1}-x)^{3}}{6h_{j}}+M_{j+1}\frac{(x-x_{j})^{3}}{6h_{j}}+(y_{j}-\frac{M_{j}h_{j}^{2}}{6})\frac{x_{j+1}-x}{h_{j}}+(y_{j+1}-\frac{M_{j+1}h_{j}^{2}}{6})\frac{x-x_{j}}{h_{j}}$
对上式求导得到:
$S^{‘}(x)=-M_{j}\frac{(x_{j+1}-x)^{2}}{2h_{j}}+M_{j+1}\frac{(x-x_{j})^{2}}{2h_{j}}+\frac{y_{j+1}-y_{j}}{h_{j}}-\frac{M_{j+1}-M_{j}}{6}h_{j}$
根据在$x_{j},1\leq j\leq n-1$处一阶导数相等可得:
$\mu_{j}M_{j-1}+2M_{j}+\lambda _{j}M_{j+1}=d_{j},1\leq j\leq n-1$
其中$\mu_{j}=\frac{h_{j-1}}{h_{j-1}+h_{j}}$,$\lambda _{j}=\frac{h_{j}}{h_{j-1}+h_{j}}$,$d_{j}=6\frac{f[x_{j},x_{j+1}]-f[x_{j-1},x_{j}]}{h_{j-1}+h_{j}}$,$f[x_{j},x_{j+1}]=\frac{y_{j+1}-y_{j}}{x_{j+1}-x{j}}$

同时对于边界条件$S^{‘}(x_{0})=f^{‘}(x_{0})$,$S^{‘}(x_{n})=f^{‘}(x_{n})$可得:$2M_{0}+M_{1}=\frac{6}{h_{0}}(f[x_{0},x_{1}]-f^{‘}(x_{0}))$,$M_{n-1}+2M_{n}=\frac{6}{h_{n-1}}(f^{‘}(x_{n})-f[x_{n-1},x_{n}])$.

#include <cstdio>#include <cstdlib>#include <algorithm>#include <cmath>#include <cassert>#include <ctime>class MclVector{public:    int n;    double *Mat;    /**      type=0: 列向量      type=1: 行向量    **/    int type;    MclVector() { Mat=NULL; n=0; }    MclVector(int len,double initVal=0.0)    {        n=len;        Mat=new double[n+1];        for(int i=0;i<=n;i++) Mat[i]=initVal;        type=0;    }    double operator[](int id) const    {        return Mat[id];    }    double& operator[](int id)    {        return Mat[id];    }    double length() const    {        double sum=0;        for(int i=1;i<=n;i++) sum+=Mat[i]*Mat[i];        return sqrt(sum);    }    MclVector operator*(double val) const    {        MclVector ans=MclVector(n);        for(int i=1;i<=n;i++) ans[i]=Mat[i]*val;        return ans;    }    MclVector operator/(double val) const    {        MclVector ans=MclVector(n);        for(int i=1;i<=n;i++) ans[i]=Mat[i]/val;        return ans;    }    MclVector operator+(const MclVector &newVector) const    {        MclVector ans=MclVector(n);        for(int i=1;i<=n;i++) ans[i]=Mat[i]+newVector[i];        return ans;    }    MclVector operator-(const MclVector &newVector) const    {        MclVector ans=MclVector(n);        for(int i=1;i<=n;i++) ans[i]=Mat[i]-newVector[i];        return ans;    }    MclVector operator*=(double val)    {        for(int i=1;i<=n;i++) Mat[i]=Mat[i]*val;        return *this;    }    MclVector operator/=(double val)    {        for(int i=1;i<=n;i++) Mat[i]=Mat[i]/val;        return *this;    }    MclVector operator+=(const MclVector &newVector)    {        for(int i=1;i<=n;i++) Mat[i]+=newVector[i];        return *this;    }    MclVector operator-=(const MclVector &newVector)    {        for(int i=1;i<=n;i++) Mat[i]-=newVector[i];        return *this;    }    MclVector GetTranspose() const    {        MclVector ans=*this;        ans.type=1;        return ans;    }    void print() const    {        for(int i=1;i<=n;i++) printf("%8.3lf ",Mat[i]);        puts("");    }};class MclMatrix{public:    int row,col;    MclVector *Mat;    MclMatrix() {Mat=NULL;}    MclMatrix(int _row,int _col,double initVal=0.0)    {        row=_row;        col=_col;        Mat=new MclVector[row+1];        for(int i=0;i<=row;i++) Mat[i]=MclVector(col,initVal);    }    void setIdentityMatrix()    {        for(int i=1;i<=row;i++)        {            for(int j=1;j<=col;j++)            {                if(i==j) Mat[i][j]=1;                else Mat[i][j]=0;            }        }    }    MclMatrix GetTranspose() const    {        MclMatrix ans=MclMatrix(col,row);        for(int i=1;i<=ans.row;i++)        {            for(int j=1;j<=ans.col;j++)            {                ans[i][j]=Mat[j][i];            }        }        return ans;    }    void print() const    {        for(int i=1;i<=row;i++) Mat[i].print();        puts("");    }    MclVector& operator[](int id) const    {        return Mat[id];    }    MclVector& operator[](int id)    {        return Mat[id];    }    MclMatrix operator*(const MclMatrix &Matrix) const    {        MclMatrix ans=MclMatrix(row,Matrix.col);        for(int i=1;i<=row;i++)        {            for(int j=1;j<=Matrix.col;j++)            {                for(int k=1;k<=col;k++)                {                    ans[i][j]+=Mat[i][k]*Matrix[k][j];                }            }        }        return ans;    }    MclMatrix operator+(const MclMatrix &Matrix) const    {        MclMatrix ans=MclMatrix(row,Matrix.col);        for(int i=1;i<=row;i++)        {            for(int j=1;j<=Matrix.col;j++)            {                ans[i][j]=Mat[i][j]+Matrix[i][j];            }        }        return ans;    }    MclMatrix operator-(const MclMatrix &Matrix) const    {        MclMatrix ans=MclMatrix(row,Matrix.col);        for(int i=1;i<=row;i++)        {            for(int j=1;j<=Matrix.col;j++)            {                ans[i][j]=Mat[i][j]-Matrix[i][j];            }        }        return ans;    }    MclVector GetCol(int colId) const    {        MclVector ans=MclVector(row);        for(int i=1;i<=row;i++) ans[i]=Mat[i][colId];        return ans;    }    MclVector GetRow(int rowId) const    {        MclVector ans=MclVector(row);        for(int i=1;i<=col;i++) ans[i]=Mat[rowId][i];        return ans;    }    MclMatrix operator*=(const MclMatrix &Matrix)    {        return *this=*this*Matrix;    }    MclMatrix operator+=(const MclMatrix &Matrix)    {        return *this=*this+Matrix;    }    MclMatrix operator-=(const MclMatrix &Matrix)    {        return *this=*this-Matrix;    }    MclMatrix operator*(double x) const    {        MclMatrix ans=*this;        for(int i=1;i<=row;i++)        {            for(int j=1;j<=col;j++)            {                ans[i][j]*=x;            }        }        return ans;    }};MclMatrix vectorMulVector(const MclVector &A,const MclVector& B){    if(A.type==0)    {        MclMatrix ans=MclMatrix(A.n,B.n);        for(int i=1;i<=A.n;i++)        {            for(int j=1;j<=B.n;j++)            {                ans[i][j]+=A[i]*B[j];            }        }        return ans;    }    else    {        assert(A.n==B.n);        MclMatrix ans=MclMatrix(1,1);        for(int i=1;i<=A.n;i++)        {            ans[1][1]+=A[i]*B[i];        }        return ans;    }}int sgn(double x){    if(x<-0.000001) return -1;    if(x>0.000001) return 1;    return 0;}/**  高斯消去 A为n*n B为n*1**/MclVector Gauss(MclMatrix A,MclVector B){    const int n=A.row;    const int m=A.col;    assert(m==B.n&&m==n);    MclVector ans=MclVector(m);    for(int i=1;i<=n;i++)    {        int row=i;        for(int j=i;j<=n;j++)        {            if(sgn(A[j][i]))             {                row=i; break;            }        }        if(row!=i)         {            for(int j=1;j<=n;j++) std::swap(A[i][j],A[row][j]);            std::swap(B[i],B[row]);        }        for(int j=1;j<=n;j++) if(i!=j)        {            const double det=A[j][i]/A[i][i];            for(int k=i;k<=n;k++) A[j][k]-=det*A[i][k];            B[j]-=det*B[i];        }    }    for(int i=1;i<=n;i++) ans[i]=B[i]/A[i][i];    return ans;}/**  n: 点个数[0,n]  RangeSplitPos: 分界点 大小(n+1)  SplitPosValue: 函数值 大小(n+1)  LValue,RValue: 两侧的一阶导数  返回值: 每个区间的多项式 大小n**/std::vector<Polynomial> CubicSplineInterpolation(    const int n,    const std::vector<double> RangeSplitPos,    const std::vector<double> SplitPosValue,    const double LValue,    const double RValue){#define x(i) RangeSplitPos[i]#define y(i) SplitPosValue[i]#define h(i) (RangeSplitPos[i+1]-RangeSplitPos[i])#define f(i,j) ((y(j)-y(i))/h(i))    double *mou=new double[n+1];    double *lamd=new double[n+1];    double *d=new double[n+1];    memset(mou,0,sizeof(double)*(n+1));    memset(lamd,0,sizeof(double)*(n+1));    memset(d,0,sizeof(double)*(n+1));    lamd[0]=1;    d[0]=6.0/h(0)*(f(0,1)-LValue);    mou[n]=1;    d[n]=6.0/h(n-1)*(RValue-f(n-1,n));    for(int j=1;j<=n-1;j++)    {        mou[j]=h(j-1)/(h(j-1)+h(j));        lamd[j]=h(j)/(h(j-1)+h(j));        d[j]=6.0/(h(j-1)+h(j))*(f(j,j+1)-f(j-1,j));    }    MclMatrix A=MclMatrix(n+1,n+1);    for(int i=1;i<=n+1;i++)    {        if(i>1) A[i][i-1]=mou[i-1];        if(i<n+1) A[i][i+1]=lamd[i-1];        A[i][i]=2;    }    MclVector B=MclVector(n+1);    for(int i=1;i<=n+1;i++) B[i]=d[i-1];    delete[] mou;    delete[] lamd;    delete[] d;    MclVector MArr=Gauss(A,B);    std::vector<Polynomial> LastAns;    for(int j=0;j<n;j++)    {        const double Mj=MArr[j+1];        const double Mj1=MArr[j+2];        Polynomial poly;        double tmp=-Mj/(6.0*h(j));        poly.add(3,tmp);        poly.add(2,-3*x(j+1)*tmp);        poly.add(1,3*x(j+1)*x(j+1)*tmp);        poly.add(0,-x(j+1)*x(j+1)*x(j+1)*tmp);        tmp=Mj1/(6*h(j));        poly.add(3,tmp);        poly.add(2,-3*x(j)*tmp);        poly.add(1,3*x(j)*x(j)*tmp);        poly.add(0,-x(j)*x(j)*x(j)*tmp);        tmp=(y(j)-Mj*h(j)*h(j)/6.0)/h(j);        poly.add(0,tmp*x(j+1));        poly.add(1,-tmp);        tmp=(y(j+1)-Mj1*h(j)*h(j)/6.0)/h(j);        poly.add(0,-tmp*x(j));        poly.add(1,tmp);        LastAns.push_back(poly);    }    return LastAns;}

 

三次样条插值