赞
踩
目录
主要研究对象:二阶线性常微分方程边值问题。
即形如式(1)和(2)的问题计算。其中为已知函数,为待求函数,为常数。
公式(1)中的边值条件称为狄利克雷边界条件(Dirichlet),公式(2)中的边值条件称为混合边界条件,当时,称为诺依曼边界条件(Neumann)。
基本思想:将公式(1)转化为与之等价的初值问题,利用假设的待定系数来确定这种转化。
先将公式(1)转化为等价的初值问题:
其中为常数,待定。为了确定,需要对公式(3)进行分解,该初值问题的解可以通过两个齐次方程和一个非齐次方程来确定,如下:
假设上述三式的解分别为,根据线性微分方程解的结构可知公式(3)的解为。由于公式(1)与公式(3)等价,故公式(3)的解应该满足公式(1)的边界条件,自然满足,还需满足。于是得到:
于是, 求解的基本流程为:
①将边值问题分解为3个等价的初值问题,得到3个数值解,初值问题的解法可以任选(通常采用四阶龙格-库塔法,确保计算精度),且假设这3个数值解为,分别对应精确解为,精度为四阶。
②用龙格-库塔法求解得到的是在各节点处的值,记作,于是待定系数。
③利用得到公式(3),也是公式(1)的精确解在节点处的数值解。
求解两点边值问题:
步长h=0.1。已知精确解为:。
代码如下:
- #include <cmath>
- #include <stdlib.h>
- #include <stdio.h>
-
- int N;
- double h;
-
- int main(int argc, char* argv[])
- {
- int i;
- double a,b,alpha,beta,gamma;
- double *x,*y,*y1,*y2,*y3;
- double p(double x);
- double q(double x);
- double f(double x);
- double *rhsf(int k, double x, double y1, double y2);
- double *RKhigher(int k, double *x, double c, double d);
- double exact(double x);
-
- a=0.0;
- b=1.0;
- N=10;
- h=(b-a)/N;
- x=(double *)malloc(sizeof(double)*(N+1));
- for(i=0;i<=N;i++)
- x[i]=a+i*h;
-
- alpha=0.0;beta=0.0;
-
- y1=RKhigher(0,x,1,0);
- y2=RKhigher(0,x,0,1);
- y3=RKhigher(1,x,0,0);
-
- y=(double *)malloc(sizeof(double)*(N+1));
- gamma=(beta-alpha*y1[N]-y3[N])/y2[N];
- for(i=1;i<=N;i++)
- {
- y[i]=alpha*y1[i]+gamma*y2[i]+y3[i];
- printf("x[%d]=%.2f, y=%f, exact=%f, error=%.4e.\n",i,x[i],y[i],exact(x[i]),fabs(exact(x[i])-y[i]));
- }
-
- return 0;
- }
-
- double p(double x)
- {
- return 0.0;
- }
-
- double q(double x)
- {
- return 1.0;
- }
-
- double f(double x)
- {
- return -1.0;
- }
-
- double *rhsf(int k, double x, double y1, double y2)
- {
- double *z;
- z=(double *)malloc(sizeof(double)*2);
- z[0]=y2;
- z[1]=k*f(x)-p(x)*y2-q(x)*y1;
- return z;
- }
-
- double *RKhigher(int k, double *x, double c, double d)
- {
- int i;
- double *y,y1,y2,*k1,*k2,*k3,*k4;
- y=(double*)malloc(sizeof(double)*(N+1));
- y[0]=c;
- y1=c;
- y2=d;
- for(i=0;i<N;i++)
- {
- k1=rhsf(k,x[i],y1,y2);
- k2=rhsf(k,x[i]+0.5*h,y1+0.5*h*k1[0],y2+0.5*h*k1[1]);
- k3=rhsf(k,x[i]+0.5*h,y1+0.5*h*k2[0],y2+0.5*h*k2[1]);
- k4=rhsf(k,x[i+1],y1+h*k3[0],y2+h*k3[1]);
- y1=y1+h*(k1[0]+2*k2[0]+2*k3[0]+k4[0])/6.0;
- y2=y2+h*(k1[1]+2*k2[1]+2*k3[1]+k4[1])/6.0;
- y[i+1]=y1;
- free(k1);free(k2);free(k3);free(k4);
- }
- return y;
- }
-
- double exact(double x)
- {
- return cos(x)+(1-cos(1.0))*sin(x)/sin(1.0)-1;
- }
N=10时,运行结果如下:
- x[1]=0.10, y=0.049543, exact=0.049543, error=8.9716e-08.
- x[2]=0.20, y=0.088600, exact=0.088600, error=1.6175e-07.
- x[3]=0.30, y=0.116780, exact=0.116780, error=2.1458e-07.
- x[4]=0.40, y=0.133801, exact=0.133801, error=2.4707e-07.
- x[5]=0.50, y=0.139494, exact=0.139494, error=2.5845e-07.
- x[6]=0.60, y=0.133801, exact=0.133801, error=2.4836e-07.
- x[7]=0.70, y=0.116780, exact=0.116780, error=2.1683e-07.
- x[8]=0.80, y=0.088600, exact=0.088600, error=1.6430e-07.
- x[9]=0.90, y=0.049543, exact=0.049543, error=9.1615e-08.
- x[10]=1.00, y=-0.000000, exact=0.000000, error=5.5511e-17.
我们采取同样的思路,将其转化为等价的初值问题,如:
其中s,t为常数,待定。是上式的解,按照等价条件可以确定:
于是, 求解的基本流程为:
①降阶化为一阶方程组并分别数值求解常微分方程的初值问题,得到的数值解分别为。由于二阶初值问题通过引入降阶后就可以将数值求解,从而得到对应的各导数值的近似值。
②数值解都是离散的,第一步得到的是在各点处的值,分别记作,于是待定常数s,t为:
③确定s,t后,再利用得到在节点处的数值解。
求解两点边值问题:
步长h=π/10。已知精确解为:。
代码如下:
- #include <cmath>
- #include <stdlib.h>
- #include <stdio.h>
- #define PI 3.14159265359
-
- int N;
- double h;
-
- int main(int argc, char* argv[])
- {
- int i;
- double a,b,alpha,beta,lammda,mu,s,t,eta1,eta2,eta3,temp;
- double *x,*y,*y1,*y2,*y3;
- double p(double x);
- double q(double x);
- double f(double x);
- double *rhsf(int k, double x, double y1, double y2);
- double *RKhigher(int k, double *x, double c, double d);
- double exact(double x);
-
- a=0.0;
- b=PI;
- N=10;
- h=(b-a)/N;
- x=(double *)malloc(sizeof(double)*(N+1));
- for(i=0;i<=N;i++)
- x[i]=a+i*h;
-
- lammda=-2.0;mu=1.0;alpha=1.0;beta=-exp(PI);
- y1=RKhigher(0,x,1,0);
- y2=RKhigher(0,x,0,1);
- y3=RKhigher(1,x,0,0);
- eta1=y1[2*N+1]+mu*y1[N];
- eta2=y2[2*N+1]+mu*y2[N];
- eta3=y3[2*N+1]+mu*y3[N];
- temp=lammda*eta2-eta1;
- s=(alpha*eta2-beta+eta3)/temp;
- t=(lammda*beta-alpha*eta1-lammda*eta3)/temp;
- y=(double*)malloc(sizeof(double)*(N+1));
- for(i=0;i<=N;i++)
- {
- y[i]=s*y1[i]+t*y2[i]+y3[i];
- printf("x[%d]=%.2f, y=%f. exact=%f, error=%.4e.\n",i,x[i],y[i],exact(x[i]),fabs(exact(x[i])-y[i]));
- }
-
- return 0;
- }
-
-
- double p(double x)
- {
- return x;
- }
- double q(double x)
- {
- return -x;
- }
- double f(double x)
- {
- return (x+2)*exp(x)*cos(x);
- }
- double *rhsf(int k, double x, double y1, double y2)
- {
- double *z;
- z=(double*)malloc(sizeof(double)*2);
- z[0]=y2;
- z[1]=k*f(x)-p(x)*y2-q(x)*y1;
- return z;
- }
- double *RKhigher(int k, double *x, double c, double d)
- {
- int i;
- double *y,*z,*w,y1,y2,*k1,*k2,*k3,*k4;
- y=(double*)malloc(sizeof(double)*(N+1));
- z=(double*)malloc(sizeof(double)*(N+1));
-
- y[0]=c;
- z[0]=d;
- y1=c;
- y2=d;
- for(i=0;i<N;i++)
- {
- k1=rhsf(k,x[i],y1,y2);
- k2=rhsf(k,x[i]+0.5*h,y1+0.5*h*k1[0],y2+0.5*h*k1[1]);
- k3=rhsf(k,x[i]+0.5*h,y1+0.5*h*k2[0],y2+0.5*h*k2[1]);
- k4=rhsf(k,x[i+1],y1+h*k3[0],y2+h*k3[1]);
- y1=y1+h*(k1[0]+k2[0]*2+k3[0]*2+k4[0])/6.0;
- y2=y2+h*(k1[1]+k2[1]*2+k3[1]*2+k4[1])/6.0;
- y[i+1]=y1;
- z[i+1]=y2;
- free(k1);free(k2);free(k3);free(k4);
- }
-
- w=(double*)malloc(sizeof(double)*(2*N+2));
- for(i=0;i<=N;i++)
- {
- w[i]=y[i];
- w[N+1+i]=z[i];
- }
- free(y);free(z);
- return w;
- }
- double exact(double x)
- {
- return exp(x)*sin(x);
- }
N=10时,运行结果如下:
- x[0]=0.00, y=0.001062. exact=0.000000, error=1.0622e-03.
- x[1]=0.31, y=0.424819. exact=0.423078, error=1.7411e-03.
- x[2]=0.63, y=1.104218. exact=1.101778, error=2.4400e-03.
- x[3]=0.94, y=2.079446. exact=2.076207, error=3.2394e-03.
- x[4]=1.26, y=3.345909. exact=3.341619, error=4.2907e-03.
- x[5]=1.57, y=4.816274. exact=4.810477, error=5.7967e-03.
- x[6]=1.88, y=6.271685. exact=6.263717, error=7.9679e-03.
- x[7]=2.20, y=7.305872. exact=7.294929, error=1.0943e-02.
- x[8]=2.51, y=7.271028. exact=7.256376, error=1.4653e-02.
- x[9]=2.83, y=5.241622. exact=5.223013, error=1.8609e-02.
- x[10]=3.14, y=0.021620. exact=-0.000000, error=2.1620e-02.
首先考虑形如式(5)的两点狄利克雷边值问题:
其中为已知函数且在[a,b]内,为待求函数,为常数。首先对求解域[a,b]等距剖分,得到m+1个节点,步长为。然后将院复查弱化,使其在内部节点成立,有:
再对二阶导数值进行处理,可得到在节点处的离散方程:
其中。忽略其中的高阶项,用数值解作为精确解的近似值,结合边界条件,可得:
这是一个由m-1个未知量、个方程构成的线性方程组,可以写成矩阵的形式:
由于,所以上述方程组系数矩阵是一个对角占优的三对角矩阵,可使用追赶法直接求解。
求解两点边值问题:
步长h=π/16,计算节点处的数值解,并给出与精确解的误差。
代码如下:
- #include <cmath>
- #include <stdlib.h>
- #include <stdio.h>
-
- int main(int argc, char* argv[])
- {
- int i,j,N;
- double a,b,h,Pi,alpha,beta;
- double *matrix_a_array,*matrix_b_array,*x,*y,*rhs,*ans;
- double f(double x);
- double q(double x);
- double *chase_algorithm(double *a, double *b, double *c, double *d, int n);
- double exact(double x);
-
- N=8;
- Pi=3.14159265359;
- a=0.0;
- b=Pi/2.0;
- h=(b-a)/N;
- alpha=0.0;
- beta=1.0;
-
- x=(double*)malloc(sizeof(double)*(N+1));
- for(i=0;i<=N;i++)
- x[i]=a+i*h;
-
- rhs=(double*)malloc(sizeof(double)*(N-1));
- for(i=1;i<N;i++)
- rhs[i-1]=h*h*f(x[i]);
-
- rhs[0]=rhs[0]-alpha;
- rhs[N-2]=rhs[N-2]-beta;
-
- matrix_a_array=(double*)malloc(sizeof(double)*(N-1));
- matrix_b_array=(double*)malloc(sizeof(double)*(N-1));
- for(i=0;i<N-1;i++)
- {
- matrix_a_array[i]=1.0;
- matrix_b_array[i]=h*h*q(x[i+1])-2;
- }
- ans=chase_algorithm(matrix_a_array,matrix_b_array,matrix_a_array,rhs,N-1);
- free(matrix_a_array);free(matrix_b_array);free(rhs);
-
- y=(double*)malloc(sizeof(double)*(N+1));
- y[0]=alpha;
- for(i=1;i<N;i++)
- y[i]=ans[i-1];
- free(ans);
- y[N]=beta;
-
- j=N/4;
- for(i=0;i<=N;i=i+j)
- printf("x=%.2f,y=%f,exact=%f,err=%.4e.\n",x[i],y[i],exact(x[i]),fabs(exact(x[i])-y[i]));
-
- return 0;
- }
-
-
- double f(double x)
- {
- return -(x*x-x+5.0/4.0)*sin(x);
- }
- double q(double x)
- {
- double z;
- z=x-0.5;
- return -z*z;
- }
- double* chase_algorithm(double *a, double *b, double *c, double *d, int n)
- {
- int i;
- double *ans,*g,*w,p;
-
- ans=(double*)malloc(sizeof(double)*n);
- g=(double*)malloc(sizeof(double)*n);
- w=(double*)malloc(sizeof(double)*n);
- g[0]=d[0]/b[0];
- w[0]=c[0]/b[0];
-
- for(i=1;i<n;i++)
- {
- p=b[i]-a[i]*w[i-1];
- g[i]=(d[i]-a[i]*g[i-1])/p;
- w[i]=c[i]/p;
- }
- ans[n-1]=g[n-1];
- i=n-2;
- do
- {
- ans[i]=g[i]-w[i]*ans[i+1];
- i=i-1;
- }while(i>=0);
- free(g);free(w);
-
- return ans;
- }
- double exact(double x)
- {
- return sin(x);
- }
N=8时,运行结果如下:
- x=0.00,y=0.000000,exact=0.000000,err=0.0000e+00.
- x=0.39,y=0.383096,exact=0.382683,err=4.1273e-04.
- x=0.79,y=0.707746,exact=0.707107,err=6.3923e-04.
- x=1.18,y=0.924409,exact=0.923880,err=5.2906e-04.
- x=1.57,y=1.000000,exact=1.000000,err=0.0000e+00.
考虑形如式(6)的两点混合边值问题:
式(6)在离散节点处的方程为:
对其中内部节点的二阶导数采用二阶差商,起点、终点处的一阶导数分别采用向前、向后差商,忽略高阶项,并用数值解代替精确解,可得差分格式:
可将上式写成矩阵形式:
=
该矩阵为m+1阶的三对角线性方程组,用追赶法求解。
求解两点混合边值问题:
步长h=1/4。计算节点处的数值解,并给出与精确解的误差。
代码如下:
- #include <cmath>
- #include <stdlib.h>
- #include <stdio.h>
-
- int main(int argc, char* argv[])
- {
- int i,j,N;
- double a,b,h,alpha,beta,lambda,mu;
- double *matrix_a_array,*matrix_b_array,*x,*y,*rhs;
- double f(double x);
- double q(double x);
- double *chase_algorithm(double *a, double *b, double *c, double *d, int n);
- double exact(double x);
-
- a=0.0;
- b=1.0;
- N=4;
- h=(b-a)/N;
- alpha=0.0;
- beta=3*exp(1.0);
- lambda=-1.0;
- mu=2.0;
-
- x=(double*)malloc(sizeof(double)*(N+1));
- for(i=0;i<=N;i++)
- x[i]=a+i*h;
-
- rhs=(double*)malloc(sizeof(double)*(N+1));
- rhs[0]=h*alpha;
- for(i=1;i<N;i++)
- rhs[i]=h*h*f(x[i]);
- rhs[N]=-h*beta;
-
- matrix_a_array=(double*)malloc(sizeof(double)*(N+1));
- matrix_b_array=(double*)malloc(sizeof(double)*(N+1));
- for(i=0;i<=N;i++)
- {
- matrix_a_array[i]=1.0;
- matrix_b_array[i]=h*h*q(x[i])-2;
- }
- matrix_b_array[0]=h*lambda-1.0;
- matrix_b_array[N]=-(h*mu+1.0);
-
- y=chase_algorithm(matrix_a_array,matrix_b_array,matrix_a_array,rhs,N+1);
- free(matrix_a_array);free(matrix_b_array);free(rhs);
-
- j=N/4;
- for(i=0;i<=N;i=i+j)
- printf("x=%.2f,y=%f,exact=%f,err=%f.\n",x[i],y[i],exact(x[i]),fabs(exact(x[i])-y[i]));
- free(x);free(y);
-
- return 0;
- }
-
-
- double f(double x)
- {
- return -exp(x)*sin(x);
- }
- double q(double x)
- {
- return -(1+sin(x));
- }
- double *chase_algorithm(double *a, double *b, double *c, double *d, int n)
- {
- int i;
- double *ans,*g,*w,p;
-
- ans=(double*)malloc(sizeof(double)*n);
- g=(double*)malloc(sizeof(double)*n);
- w=(double*)malloc(sizeof(double)*n);
- g[0]=d[0]/b[0];
- w[0]=c[0]/b[0];
-
- for(i=1;i<n;i++)
- {
- p=b[i]-a[i]*w[i-1];
- g[i]=(d[i]-a[i]*g[i-1])/p;
- w[i]=c[i]/p;
- }
-
- ans[n-1]=g[n-1];
- i=n-2;
- do
- {
- ans[i]=g[i]-w[i]*ans[i+1];
- i=i-1;
- }while(i>=0);
-
- free(g);free(w);
- return ans;
- }
- double exact(double x)
- {
- return exp(x);
- }
N=4时,运行结果如下:
- x=0.00,y=1.104528,exact=1.000000,err=0.104528.
- x=0.25,y=1.380660,exact=1.284025,err=0.096635.
- x=0.50,y=1.744578,exact=1.648721,err=0.095856.
- x=0.75,y=2.220404,exact=2.117000,err=0.103404.
- x=1.00,y=2.839410,exact=2.718282,err=0.121128.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。