计算方法汇总

一、内容简介

     

本次报告,是在完成整个学期的计算方法学习之后做出的一次一小组为单位的总体汇报,我们汇报的内容主要是建立在以全英文教材《剑桥数值方法教材》学习的基础上,对教材的四块主要内容经行编程实现、组内交流、组间汇报、汇报总结等学习讨论之后进行的一次总结归纳。此次报告主要分为四大部分,第一部分我们将着重讲解一下计算方法课程的授课方式和小组内的学习情况,第二部分我们主要讲述一下课程的主要内容和我们对计算方法经行的一下课外的拓展,第三部分我们将展示一下我们组内的成员对计算方法的学习和授课方式的感受,第四部分我们将回顾一学期的学习组长经行一下小组的一个学习总结。此次报告我们不局限于教材上所学的知识,通过多个算法的比较,我们尝试着探究效率更高、时间空间更加优化的算法。于是,我们经行的广泛的查询,虽然时间不是很充裕,在研究方面也是很浅显,但是我们不会以此次报告为一个终结点,而是组织组内有兴趣的人继续下去,对计算方法这门课程有一个更加深入的了解。

二、前言

计算方法又称“数值分析”,是为各种数学问题的数值解答研究提供最有效的算法。主要内容为函数逼近论,数值微分、数值积分,误差分析等。常用方法有迭代法、差分法、插值法、有限元素法、线性方程组等。现代的计算方法还要求适应电子计算机的特点。

本课程是信息与计算科学、数学与应用数学本科专业必修的一门专业基础课,我们需在掌握数学分析、高等代数和常微分方程的基础知识之上,学习本课程。 “计算方法”是专门研究各种数学问题的近似解的一门课程,通过这门课程的教学,使学生掌握用数值分析方法解决实际问题以及算法原理和理论分析,提高我们应用数学知识解决实际问题的能力。

对于这门课程的学习,我们采取的是“大班授课,小组合作”的教学方式,即在承认课堂教学为基本教学组织形式的前提下,教师以学生学习小组为重要的教学组织手段,通过指导小组成员展开合作,形成“组内成员合作,组间成员竞争”的学习模式,发挥群体的积极功能,提高个体的学习动力和能力,达到完成特定的教学任务的目的,更好的帮助小组成员完成学习任务和教学任务。同时在组间实行竞争机制更能有效的调动学生的参与热情和学习积极性,培养学生的竞争意识。我们使用的是剑桥数值方法教材,在学习计算方法课程的同时,也进一步提高了我们的英语水平,此乃一举两得,使用全英文教材使我们直接接触到当前国际上最先进的剖析和见解,避免了中文翻译带来的错误和问题复杂化。

本小组一共有11位成员,在组长的英明领导下,一共成功进行了四次精彩的实习报告,每一次实习过程中,大家伙都积极参与,勇于表现,各尽其责,基本上人人都会写出一份自己的程序并上机演示,积极与小组成员讨论、改进、升华,最后由组长进行总结,筛选出最有特色、最具健壮性、最好的程序作为本小组进行报告的内容,并安排各小组成员的后续工作,如做PPT、写报告、定发言人等,确保每位小组成员都有事可做,发挥自己的特长,实现自己的价值。一切的一切都是为了能让该次实习报告做到最好,体现出本组强大的实力以及各成员强烈的积极性和责任心,发挥出团队最大的力量。

感谢曾三友老师能给我们这样一次机会体验小组合作所带来的收获和喜悦,不仅培养我们的合作意识、团队精神、理性思考、同时也提升我们的境界拓宽我们的胸怀,尺有所短寸有所长,要多发现和挖掘各自的优势和长处,求知的过程要提倡个人资源互补、优势共享才能少走弯路,携手共赢。同时也非常感谢组内所有成员,正是因为大家伙的齐心协力,众志成城,不分彼此,团结合作,互利共赢,共同成长,才取得了这样不错的成绩,谢谢大家。

由于小组水平所限,不当之处在所难免,欢迎老师还有各位同学批评指正,在下代表本组成员感激不尽。

三、目录

一、内容简介—————————————————— 02

二、前言———————————————————— 03

三、目录———————————————————— 04

三、主要内容—————————————————— 05

    1、计算方法概要——————————————— 05

    2、方程求根    ——————————————— 06

3、方程组求解  ——————————————— 12

    4、方程积分    ——————————————— 23

5、方程微分    ——————————————— 39

五、结课感言—————————————————— 46

小组总结      ——————————————— 46

小组成员感言  ——————————————— 47

六、小组分工—————————————————— 52

七、总结———————————————————— 54

四、主要内容

计算方法概要

介绍一下什么是计算方法

    现代科学发展依赖于理论研究、科学实验与科学计算三种主要手段,它们相辅相成,可以互相补充又都不可缺少。由于计算机技术的发展及其在各技术科学领域的应用推广与深化,新的计算性学科分支纷纷兴起,如计算力学、计算物理、计算化学、计算经济学等等,不论其背景与含义如何,要用计算机进行科学计算都必须建立相应的数学模型,并研究其适合于计算机编程的计算方法。“数值计算方法”是计算数学的一个主要部分。伴随着计算机技术的飞速发展和计算数学方法与理论的日益成熟,科学计算已成为第三种科学研究的方法和手段。数值计算方法是研究怎样利用计算工具来求出数学问题的数值解,并对算法的收敛性、稳定性和误差进行分析、计算的全过程。

数值计算方法,简称计算方法,又称“数值分析”。是在计算机上使用的解数学问题的方法,数值分析的目的是设计及分析一些计算的方式,可针对一些问题得到近似但够精确的结果,为各种数学问题的数值解答研究提供最有效的算法。数值计算方法是微分方程,常微分方程,线性方程组的求解,主要内容为函数逼近论,数值微分,数值积分,求解线性方程组, 计算矩阵特征值和特征向量,常微分方程数值解,误差分析等,常用方法有迭代法、差分法、插值法、有限元素法等,计算对象是微积分线性代数,常微分方程中的数学问题。

在使用计算方法解决实际问题的过程中,往往需要把连续型离散化处理,同时离散形式的解可以近似原来的连续模型的解。例如:求一个函数的积分是一个连续模型的问题,也就是求一曲线以下的面积,若将其离散化变成数值积分,就变成将上述面积用许多较简单的形状(如矩形、梯形、抛物线)近似,因此只要求出这些形状的面积然后累加即可。离散化是程序设计中一个很常用的技巧,它可以有效的降低时间复杂度。在学习数值积分时,Trapezium rule、Mid-point rule、Simpson’s rule、Gauss quadrature等方法都体现了离散化的思想,降低了解决实际问题过程中的难度。

计算方法和计算机的结合

利用计算机解决科学计算问题的全过程为:实际问题    构造数学模型    设计数值计算方法     程序设计    上机求出结果     回到实际问题。由流程图可以发现计算数学中的数值计算方法是解决“计算”问题的桥梁和工具,计算机与计算方法紧密联系,相辅相成,互相影响。因此在数值分析过程中,我们需要:面向计算机,要根据计算机特点提供实际可行的算法,即算法只能由计算机可执行的加减乘除四则运算和各种逻辑运算组成.

计算能力是计算工具和计算方法的效率的乘积,计算方法是研究用计算机求解数学问题的数值计算方法及其软件实现,提高计算方法的效率与提高计算机硬件的效率同样重要。计算方法与计算机发展紧密相关,现代计算数学是计算科学的核心,是各类计算性学科(计算力学、计算物理、计算化学等)的共同基础。自从计算机诞生以来,经典计算方法经历的一个重新评价、筛选、改造和创新过程,许多能充分发挥计算机潜力,有更大解题能力的新方法和新概念不断涌现,构成了现代意义下的计算方法。可见计算方法与计算机互相影响、共同发展

计算方法在实际应用中的重要性

  航天航空、地质勘探、汽车制造、桥梁设计、天气预报和汉字字样设计中都有计算方法的踪影。并且在社会生活的各个领域中,如预产期、标准体重、养老金、个人所得税等的计算都用到了计算方法。

以下是一些会利用数值分析处理的问题:数值天气预报中会用到许多先进的数值分析法。计算太空船的轨迹需要求出常微分方程的数值解。汽车公司会利用电脑模拟汽车撞击来提升汽车受到撞击时的安全性。电脑的模拟会需要求出偏微分方程的数值解。对冲基金会利用各种数值分析的工具来计算股票的市值及其变异程度。航空公司会利用复杂的最佳化算法决定票价、飞机、人员分配及用油量。此领域也称为作业研究。保险公司会利用数值软件进行精算分析。

方程求根

1、实际引用

     方程的应用无处不在,飞机为什么能够飞上天?用到了伯努利方程;生产关系中的动态平衡方程;行程的价格路程估算问题;工程的比例模型计算;会计中的利润率的计算等都用到了方程,都需要方程求解。掌握基本的方程求根的方法是很必要的,方程求根的方法包括:二分法、迭代法、牛顿法。

2、主要内容

(1)、二分法

算法描述

对方程 在[a,b]内求根。

将所给区间二分,在分点 判断是否 ;若是,则有根 。

否则,继续判断是否 ,若是,则令 ,否则令 。

否则令 。重复此过程直至求出方程 在[a,b]中的近似根为止。

代码实现

#define zero 0.0001

double f(double x)

{return 2*sin(PI*x) + cos(PI*x);}

int main()

{   double a,b;

    double x1,x2,x3;

    printf("二分法的实现\n");

    printf("例子式:2*sin(π*x)+cos(π*x)=0\n");

    printf("请输入根所在区间【】:");

    scanf("%lf %lf",&a,&b);

    printf("下界\t\t上界\t\t中间值\n");

    x1=a;

    x2=b;

    x3 = (x1+x2)/2;

    while(fabs(x2-x1)>=zero){

        printf("%lf\t%lf\t%lf\n",x1,x2,x3);

        if(f(x1)*f(x3)>0 )x1=x3;//x2=x2|| f(x1)*f(b)<0

        else if(f(x1)*f(x3)<0)x2=x3;//|| f(x1)*f(a)<0

        else printf("\t\t%.6lf\n",x1);

        x3 = (x1+x2)/2;}

    printf("结果:%.6lf\n",x3);

return 0;}

运行结果

开始界面显示为:

 

这是需要输入一个区间范围,然后在这个范围内查找方程的根,假如输入1~2的范围,程序运行后的界面为:

 

(2)、迭代法

算法描述

将方程 等价变换为 形式,并建立相应的迭代公式 。递推迭代式 ,当k趋于无穷大时,xk的极限存在,且 (xk)连续。

代码实现

#include<stdio.h>

#include<math.h>

#define zero 1e-5

double f(double x)

{

    return exp(-x);

}

int main()

{

    double x1,x2;

    printf("迭代法的实现\n");

    printf("例式:x = e(-x)\n");

    printf("请输x0的值:");

    scanf("%lf",&x1);

    x2=100;

    while(fabs(x1-x2)>=zero)

    {

                            x2=x1;

        printf("%.7lf\n",x1);

        x1 = f(x1);

    }

    return 0;

}

运行结果

该程序所求方程为:e-x-x=0可转化为x=e-x,并在x0处进行迭代

假设输入x0=1,则在x=1处进行迭代求x1,以此可求出x2x3x4···,当|xk+1-xk|<=0.00001时迭代结束,输出结果为:

最后求得方程的解为0.5671477

(3)、牛顿法

算法描述

用牛顿迭代法求f(x)=0在x0附近的一个实根的方法是:
(1) 选一个接近于x的真实根的近似根x1;
(2) 通过x1求出f(x1)。在几何上就是作x=x1,交f(x)于f(x1);
(3) 过f(x1)作 f(x)的切线,交x轴于x2。可以用公式求出x2。由于f'(x1)=f(x1)/(x2-x1),故x2=x1-f(x1)/f'(x1)

(4) 通过x2求出f(x2);
(5) 再过f(x2)作f(x)的切线交x轴于x2;
(6) 再通过x3求出f(x3),…一直求下去,直到接近真正的根。当两次求出的根之差|xn+1-xn|≤ε就认为 xn+1足够接近于真实根。
牛顿迭代公式是:xn+1=xn-f(xn)/f'(xn)

代码实现

#define zero 1e-5

double f(double x)

{

    return x-(x-exp(-x))/(1+x);

}

int main()

{

    double a;

    double x1,x2;

    printf("牛顿法的实现\n");

    printf("例式:x = e(-x)\n");

    printf("请输入x0的值:");

    scanf("%lf",&a);

    x2=a*2;

    x1=a;

              printf("%.7lf\n",x1);

    while(fabs(x1-x2)>=zero)

    {  

                            x2=x1;

        x1= f(x1);              

        printf("%.7lf\n",x1);

    }

    return 0;

}

运行结果

初始界面显示为:

该程序所求方程为:e-x-x=0可转化为x=e-x,在x0处开始迭代。

假设x0输入为1,则显示结果为:

3、算法比较

方法

优点

缺点

二分法

应用广泛,可常用于求精度不高的近似根

循环次数较多,计算量大

迭代法

计算量较小,误差小

可能不收敛

牛顿法

计算量最少,误差小

对重根收敛较慢,要求函数的一阶导数存在,可能不收敛

从以上的比较可以看出一下几点结论:

1、  二分法和迭代法、牛顿法均能解出方程的根。

2、  一般地看来,牛顿迭代法的效率较普通迭代法的要高,两点加速迭代法能加速一般迭代法。

3、  迭代法和牛顿法对初值是敏感的,若初值选择的不合适可能导致迭代的效率很低,甚至是发散的。例如,对于函数 形成的迭代,当选取初值 时,因为 是没有意义的,这样就导致了迭代的停止或发散。

4、小组讨论及分工情况

在第一次的小组讨论中,基本上每个组员都能认真的听取其他组员对程序的讲解,并在不懂的地方主动提出疑问使自己对程序的理解更深刻,觉得有些多余或者不够完善的地方提出改进的建议来帮助同学提高对算法的更多认识。在讨论过程中,每位组员都或多或少的有些收获。

在讨论之后的完成报告过程中,小组内有明确、合理的分工,让在报告某个不擅长的地方的同学和一个比较擅长的同学合作完成分配的任务,并争取每一位同学参与。最终报告的完成情况是:以肖大军的程序为基础,吸收了韩学武计算误差的方法,和陈俊桦、刘宇同学提出的计算收敛度的思想。在向胜男、方正等同学提出要将三个算法放在一起更好的比较几个算法的效率。最后由彭亚琼、杨耀鹏、张钟文、梅旭三位同学负责修改程序,王艳琴和肖大军制作展示PPT,韩学武写word文档。

方程组求解

1、实际应用

在我们的实际生活和生成当中会出现大量的方程组,在这些方程组需要求解,如果是要用人工的去求解的时候无疑是一个庞大的工作,而且很能避免错误的出现,这样会浪费大量的人力物力和时间。于是我们今天在前辈们关于方程组的求解总结出来的高斯消去法和直接三角分解法(LU分解)的基础之上借助编程过程中的循环来让计算机对方程组经行求解。这样可以节省大量的时间同时避免了错误的出现。下面将是我们本着这个目的去实现高斯消去法和直接三角分解法(LU分解)的过程。虽然有很多的难题还没有解决,但是这是我们小组共同努力的成果。

2、主要内容
1、高斯列主元消去法求解方程组

(1)、算法描述

Gauss消去法的基本思想是一次用前面的方程消去后面的未知数,从而将方程组化为等价形式:

 

这个过程就是消元,然后再回代就好了。具体过程如下:

对于 ,若 依次计算

 

然后将其回代得到:

 

以上是高斯消去法。

但是高斯消去法在消元的过程中有可能会出现 的情况,这时消元就无法进行了,即使主元数 但是很小时,其做除数,也会导致其他元素数量级的严重增长和舍入误差的扩散。因此,为了减少误差,每次消元选取系数矩阵的某列中绝对值最大的元素作为主元素。然后换行使之变到主元位置上,再进行销元计算。即高斯列主元消去法。

 

(2)、代码实现

#include<stdio.h>

#include<string.h>

#include<math.h>

#define e 0.00000001

const int M=1000;

const int N=1000;

double a[N][M];

double b[M];

double pt(int n,int m)//矩阵的输出

{

    for(int i=0;i<n;i++)

    {

        for(int j=0;j<m;j++)

        printf("%lf  ",a[i][j]);

        printf("\n");

    }

}

int jihuan(double a[N][M],int n,int m,int i)

{

    int mi=i;//最大行首

    //printf("%lf\n",a[mi][mi]);

    int x;

    for(int j=i+1;j<n;j++)

        if(fabs(a[j][i])>fabs(a[mi][i]))mi=j;//列不动

        //printf("##%d\n",mi);

    //printf("%.6f\n",a[mi][i]);

    if(mi!=i)

    for(int j=0;j<m;j++)//换行

    {

        x=a[mi][j];

        a[mi][j]=a[i][j];

        a[i][j]=x;

    }

    //printf("##\n");

    //pt(n,m);

    //printf("##\n");

    return 0;

}

int main()

{

    int n,m,zhi;

    double t;

    printf("请输入增广矩阵N,M\n");

    while(scanf("%d %d",&n,&m)!=EOF)

    {

        for(int i=0;i<n;i++)

        for(int j=0;j<m;j++)

        scanf("%lf",&a[i][j]);

        //pt(n,m);

        for(int i=0;i<n-1;i++)

    {

        jihuan(a,n,m,i);//找到不为0的因子,交换行首最大

        for(int j=i+1;j<n;j++)

       {

          if(fabs(a[j][i])>e)

          {

              t=a[j][i]/a[i][i];//对a[i][i]处理

              for(int k=i;k<m;k++)

              {

                  a[j][k]=a[j][k]-a[i][k]*t;

               }

           }

        }

        pt(n,m);printf("\n");

    }

        int j;

        for(j=0;j<m;j++)

            if(fabs(a[n-1][j])>e)break;//判断最后行是否全为0

         //printf("%lf %lf",a[n-1][m-2],a[n-1][m-1]);

        if(fabs(a[n-1][m-2])<e&&fabs(a[n-1][m-1])>e){printf("方程无解\n");continue;}

        //printf("%d %d",j,m);

        if(j==m)

        {

            for(int i=n-1;i>-1;i--)//其他行

            if(fabs(a[i][m-2])<e)n--;

        }

        if(n<m-1)//判断矩阵的秩

        {

           printf("方程有无穷多解\n");

           printf("化简后的矩阵为:\n");

           pt(n,m);

           printf("请输入拓展矩阵N,M\n");

           continue;

        }

        else if(n>m-1)

        {

            printf("方程无解\n");

            printf("化简后的矩阵为:\n");

            pt(n,m);

            printf("请输入拓展矩阵N,M\n");

            continue;

        }

         for(int i=n-1;i>0;i--)

         for(int j=i-1;j>-1;j--)

        {

            t=a[j][i]/a[i][i];

            //printf("%.2f\n",t);

            a[j][i]=a[j][i]-a[i][i]*t;//对a[i][i]处理

            a[j][m-1]-=a[i][m-1]*t;

         }

         pt(n,m);

         printf("\n");

         printf("方程的解为:");

         for(int i=0;i<n;i++)

         printf("%.3lf ",a[i][m-1]/a[i][i]);

        printf("\n请输入拓展矩阵N,M\n");

     }

    return 0;

}

(3)、运行结果

测试数据1:3 4

1 2 3 6

2 2 3 7

1 4 4 9

答案:1 1 1

 

测试数据2:3 4

0 0 1 3

3 0 0 2

0 2 0 1

答案:0.667   0.5   3

2、直接三角分解法(LU分解)求解方程组

(1)、算法描述

先将矩阵A直接分解为 则求解方程组的问题就等价于求解两个三角形方程组。

直接利用矩阵乘法,得到矩阵的三角分解计算公式为:

 

由上面的式子得到矩阵A的LU分解后,求解Ux=y的计算公式为

 

以上为LU分解法。

(2)、代码实现

#include<iostream>

#include<string.h>

using namespace std;

double m[20][20],lu[20][20];//系数,LU

double root[20],x[20],y[20];

int n;

void LU()//化解

{

    int i,j,k,t;

    double num;

    memset(lu,0,sizeof(lu));

    for(i=0;i<n;i++)//U的第一行,L的第一列处理

    {

        lu[0][i]=m[0][i];

        if(i>0)

        lu[i][0]=m[i][0]/lu[0][0];

    }

    for(i=1;i<n;i++)

    {

        for(j=i;j<n;j++)//U的第i行

        {

            num=0;

            for(t=0;t<i;t++)

            {

                //if(i-1==t) {num+=lu[t][j];continue;}

                 num+=lu[i][t]*lu[t][j];

            }

            //if(i==1) cout<<num<<endl;

            lu[i][j]=m[i][j]-num;

        }

        for(j=i+1;j<n;j++)//L的第i列

        {

            num=0;

            for(k=0;k<i;k++)

            num+=lu[j][k]*lu[k][i];

            lu[j][i]=(m[j][i]-num)/lu[i][i];

        }

    }

    cout<<endl;

    cout<<"分解后的LU矩阵为:"<<endl;

    for(i=0;i<n;i++)

    {

        for(j=0;j<n;j++)

        cout<<lu[i][j]<<" ";

        cout<<endl;

    }

    cout<<endl;

}

double iteration(int i)

//求方程组中第i个未知数的解(递推)

{

    double sum;

              if(i==0)

                            return root[0];

              else

              {

                            double sum=root[i];

                            for(int j=i-1;j>=0;j--)

                            {

                                          sum-=lu[i][j]*iteration(j);

                                          //cout<<lu[i][j]<<" ";

                            }

                            return sum;

              }

}

double iteration_root(int i)

//求方程组中第i个未知数的解

{

    double sum;

              if(i==n-1)

                            return y[n-1]/lu[i][i];

              else

              {

                            double sum=y[i];

                            for(int j=i+1;j<n;j++)

        {

            sum=(sum-lu[i][j]*iteration_root(j));

        }

        sum=sum/lu[i][i];

                            return sum;

              }

}

int main()

{

    int i,j,k,t;

    double s;

    memset(m,0,sizeof(m));

    memset(root,0,sizeof(root));

    memset(x,0,sizeof(x));

    memset(y,0,sizeof(y));

    cout<<"请输入系数矩阵的阶数"<<endl;

    cin>>n;

    cout<<"请输入系数矩阵"<<endl;

    for(i=0;i<n;i++)

    for(j=0;j<n;j++)

    cin>>m[i][j];

    cout<<"请输入结果数组"<<endl;

    for(i=0;i<n;i++)

    cin>>root[i];

    for(i=0;i<n;i++)//如果系数矩阵对角线上存在为0的元素,则对矩阵进行旋转

    {

        s=0;

       if(m[i][i]==0)

       {

           for(j=0;j<n;j++)

        {

          if(m[j][i]>s)

          {

             s=m[j][i];

             t=j;

          }

        }

        for(k=0;k<n;k++)

        {

           s=m[t][k];

           m[t][k]=m[i][k];

           m[i][k]=s;

        }

        s=root[t];

        root[t]=root[i];

        root[i]=s;

       }

    }

     LU();

    for(j=0;j<n;j++)

    {

        y[j]=iteration(j);

        cout<<"Y"<<j<<"="<<y[j]<<endl;

    }

    cout<<endl;

    for(k=n-1;k>=0;k--)

    x[k]=iteration_root(k);

    cout<<"方程解为:"<<endl;

    for(k=0;k<n;k++)

    cout<<"X"<<k<<"="<<x[k]<<endl;

    cout<<endl;

}

(3)、运行结果

实例一:

实例二:

实例三:

 

3、小组讨论及分工情况

   有了第一次方程求根时做小组汇报的经验,这次我们小组在进行小组汇报方面做了一些改变,以得到更好的效果。

首先,鉴于组内各成员的编程能力各不相同,有的同学基础较弱,编写的程序或没有写完,或运行起来会有错误、所以,我们将小组成员分成两个同学一个小组, 又编程能力强的同学带着编程能力稍弱的同学完成程序的编写,这样能确保每个同学都能学到一些编程的方法和技巧,也有助于彼此之间的共同提高。

其次,我们这次也做了组员之间任务的交换完成,也就是上一次的分工之后,我们这次决定相互的交换一下工作,然后让一些编程能力相对比较弱的同学参与到了讨论后的代码修改当中。这次的分工是:由彭亚琼、刘宇、方正、陈俊桦、韩学武五位同学负责修改程序,王艳琴和向胜男负责细化许多上台汇报的工作,张钟文和杨耀鹏写word文档,肖大军和梅旭负责制作PPT。

方程积分

1、实际应用

积分在我们日常的生活中有很广泛地应用,特别是在计算很多复杂的问题的时候,积分显示出无可替代的作用,为了满足大量的需求,这样如何用程序快速的求出积分就成了一个需要解决的问题。我们通过这次的计算方法的学习,建立在积分分割小块求面积,然后把面积加起来得到积分的近似值的原则上,将分别对trapezium rule、Mid-point rule、Simpson's rule、Gruss Qusdrature、Gruss Qusdrature-three point这五种积分方式经行效率经行比较,从而得到最好的积分方式。

2、主要的算法

1.     梯形(trapezia)公式
1、算法描述

如果用一个梯形来近似代替每个子区间的面积,梯形的四个顶点分别位于 , , 与 。梯形的面积为

                                

对于整个[a,b]区间,积分值由所有窄带的和给出

y

                                 F(x)

                     h

                                                                                           

                                            (上底+下底)*h/2=梯形面积

 

              a      xi xi+1 b                        x

2、代码实现

#define Pi 3.1415926535897931
int Trapezium(double x1,double x2)//梯形法
{
    int i,j;
    double s=0;//记和
    double x;
    double error1,error2=1;
    double Error_Ratio;//收敛性
    int intervals[20]= {1,2,4,8,16,32,64,128,256,512,1024,
    2048,4096,8192,16384,32768,65536,131072,262144,524288};//细分
    s=s+function(x1)+function(x2);
    cout<<setiosflags(ios::left)<<setw(6)<<"No."<<"             "<<
    setw(7)<<"No.f(x)"<<"       "<<setw(15)<<"Trapezium Rule"
    <<"         "<<setw(10)<<"Error Ratio"<<endl;
    for(i=0; i<20; i++)
    {
        s=function(x1)+function(x2);
        x=fabs(x2-x1)/intervals[i];
        if(x1<x2)
        {
            for(j=0; j<intervals[i]-1; j++)
                s+=2*function(x1+(j+1)*x);
        }
        else
        {
            for(j=0; j<intervals[i]-1; j++)
                s+=2*function(x2+(j+1)*x);
        }
        s=x*s/2;
        error1=s-2;
        Error_Ratio=error1/error2;
        error2=error1;
        if(i!=0)
        {
            cout<<setiosflags(ios::left)<<setw(6)<<intervals[i]
            <<"             "<<setw(7)<<intervals[i]+1<<"       "
            <<setw(15)<<error1<<"         "<<setw(10)<<Error_Ratio<<endl;
        }
        else
        {
            cout<<setiosflags(ios::left)<<setw(6)<<intervals[i]
            <<"             "<<setw(7)<<intervals[i]+1<<"       "
            <<setw(15)<<error1<<"         "<<endl;
        }
    }
    return 0;
}

3、运行结果


2.     中值发公式
1、算法描述

如果用一个矩形来近似代替每个子区间的面积,矩形的高应该用其中点,一间距为宽可以计算出矩形面积

然后同理梯形的计算方法可以得出积分。

2、代码实现

#define Pi 3.1415926535897931
//中值法
int Mid_Point(double x1,double x2)
{
    int i,j;
    double s=0,x;
    double error1,error2=1;
    double Error_Ratio;
    int intervals[20]= {1,2,4,8,16,32,64,128,256,512,1024,
    2048,4096,8192,16384,32768,65536,131072,262144,524288};
    cout<<setiosflags(ios::left)<<setw(6)<<"No."<<"             "
    <<setw(7)<<"No.f(x)"<<"       "<<setw(15)<<"Midpoint Rule"
    <<"         "<<setw(10)<<"Error Ratio"<<endl;
    for(i=0; i<20; i++)
    {
        s=0;
        x=fabs(x2-x1)/intervals[i];
        if(x1<x2)
        {
            for(j=0; j<intervals[i]; j++)
                s+=function(x1+(j+0.5)*x);
        }
        else
        {
            for(j=0; j<intervals[i]; j++)
                s+=function(x2+(j+0.5)*x);
        }
        s=x*s;
        error1=s-2;
        Error_Ratio=error1/error2;
        error2=error1;
        if(i!=0)
        {
            cout<<setiosflags(ios::left)<<setw(6)<<intervals[i]
            <<"             "<<setw(7)<<intervals[i]<<"       "
            <<setw(15)<<error1<<"         "<<setw(10)<<Error_Ratio<<endl;
        }
        else
        {
            cout<<setiosflags(ios::left)<<setw(6)<<intervals[i]
            <<"             "<<setw(7)<<intervals[i]<<"       "
            <<setw(15)<<error1<<"         "<<endl;
        }
    }
    returen 0;

}

3、运行结果
3. Simpson公式
   1、算法描述

 当积分的上下限相对于展开的中心点对称时,积分泰勒展开式中含有f(x)的奇数阶导数的项都将等于零。利用这一性质,我们可以在相邻的两个子区间内对面积作泰勒级数展开,可得

积分的精确度可以达到1。利用中心差分,可将f(x)的二阶导数近似表为

将此结果代入前述中心查分表式,则子区间[xi-1,xi+1]内的积分近似为

对于整个[a,b]区间,结果为

假设区间的数目N为偶数,则奇数格点的贡献是偶数格点贡献的2倍。这种权重上的差异来自我们为修正基本方法所得的一级结果所引入的f(x)二阶导数的贡献。而两端点 和 的权重则仅为偶数点的一半。Simpson法则的另一优点在于其自然引出了一种算法,即通过迭代使积分达到所需要的精确度。

误差估计---原则上,我们可以通过估计所省略的高阶项大小得出数值计算中的误差。其前提是知道高阶导数,这样做并不容易。比较相继的两次迭代结果是较为简便的一种方法。例如,如果两次计算值I[a,b]之差小于预设的允许值 ,则我们认为计算已经达到了所需的精确度。对于Simpson法则,该算法可通过如下方法实施。假设我们在x=a和x=b之间对函数f(x)进行积分,且要求达到精确度 。各个节点上的函数值对积分的贡献可分为三个部分,即端点区,奇数点与偶数点的贡献,

进行迭代计算,应从N= 开始,其中 应为某个较小而合理的区间数目,例如取 =6。这是迭代计算的第一步。在下一轮迭代中,将区间的数目翻倍,而令步长h减半,即令N= =2 。以这种方式改变子区间数目的好处在于,对于一个新的N,来自两个端点的贡献(存储为 )是不变的,而偶数点与上一次迭代计算过的偶数点完全相同。也就是说,在新的迭代中的 的值就是上一次循环的 与 之和。所需计算的仅仅是函数在(新的)奇数点上的值。从而我们得到结果

其中h=(b-a)/N2。利用上面等式进行变步长的循环计算即。如果计算值与前一循环所得结果之差小于ε,则可认为计算结果已收敛;否则即再次令子区间数目加倍,使N=N3=2N2。然后依此类推,直到计算结果收敛或者达到最大迭代次数

2、代码实现

#define Pi 3.1415926535897931
int Simpson(double x1,double x2)
{
    int i,j;
    double s=0,x;
    double error1,error2=1;
    double Error_Ratio;
    int intervals[20]= {1,2,4,8,16,32,64,128,256,512};
    cout<<setiosflags(ios::left)<<setw(6)<<"No."<<"             "
    <<setw(7)<<"No.f(x)"<<"       "<<setw(15)<<"Simpson Rule"
    <<"         "<<setw(10)<<"Error Ratio"<<endl;
    for(i=0; i<10; i++)
    {
        s=0;
        //n个区间 分为2n等份
        x=fabs(x2-x1)/(2*intervals[i]);
        s=s+function(x1)+function(x2);
        if(x1<x2)
        {
            for(j=1; j<2*intervals[i]; j++)
            {
                if(j%2==0)
                {
                    s+=2*function(x1+j*x);
                }
                else
                {
                    s+=4*function(x1+j*x);
                }
            }
        }
        else
        {
            for(j=1; j<2*intervals[i]; j++)
            {
                if(j%2==0)
                {
                    s+=2*function(x2+j*x);
                }
                else
                {
                    s+=4*function(x2+j*x);
                }
            }
        }
        s=s*x/3;
        error1=s-2;
        Error_Ratio=error1/error2;
        error2=error1;
        if(i!=0)
        {
            cout<<setiosflags(ios::left)<<setw(6)<<intervals[i]
            <<"             "<<setw(7)<<intervals[i]*2+1<<"       "
            <<setw(15)<<error1<<"         "<<setw(10)<<Error_Ratio<<endl;
        }
        else
        {
            cout<<setiosflags(ios::left)<<setw(6)<<intervals[i]
            <<"             "<<setw(7)<<intervals[i]*2+1<<"       "
            <<setw(15)<<error1<<"         "<<endl;
        }
    }
    return 0;

3、运行结果

4. Gruss Qusdrature及Gruss Qusdrature-three point公式
1、算法原理

在高斯求积公式(1-1)中,若取权函数p(x)=1,积分区间[-1,1]得

称之为高斯-勒让德求积公式.

对任意求积区间[a,b],通过变换

可化为区间[-1,1],这时

取a=-1,b=1,则得公式

(2-3)

求积公式的高斯点就是勒让德多项式的零点.

利用勒让德多项式的一个性质

(2-3)

按(2-2)式,可推得余项为

若取

的零点x0=0为节点,从而一点高斯-勒让德求积公式(中矩形求积公式)为

其余项为

若取

的两个零点 为节点,则

从而二点高斯-勒让德求积公式为

其余项

同理,三点高斯-勒让德求积公式为

其余项

一般地,高斯-勒让德求积公式的节点可以通过勒让德多项式的零点确定,而系数通过(2-3)式确定.

2、代码实现
int Simpson(double x1,double x2)
{
    int i,j;
    double s=0,x;
    double error1,error2=1;
    double Error_Ratio;
    int intervals[20]= {1,2,4,8,16,32,64,128,256,512};
    cout<<setiosflags(ios::left)<<setw(6)<<"No."<<"             "
    <<setw(7)<<"No.f(x)"<<"       "<<setw(15)<<"Simpson Rule"
    <<"         "<<setw(10)<<"Error Ratio"<<endl;
    for(i=0; i<10; i++)
    {
        s=0;
        //n个区间 分为2n等份
        x=fabs(x2-x1)/(2*intervals[i]);
        s=s+function(x1)+function(x2);
        if(x1<x2)
        {
            for(j=1; j<2*intervals[i]; j++)
            {
                if(j%2==0)
                {
                    s+=2*function(x1+j*x);
                }
                else
                {
                    s+=4*function(x1+j*x);
                }
            }
        }
        else
        {
            for(j=1; j<2*intervals[i]; j++)
            {
                if(j%2==0)
                {
                    s+=2*function(x2+j*x);
                }
                else
                {
                    s+=4*function(x2+j*x);
                }
            }
        }
        s=s*x/3;
        error1=s-2;
        Error_Ratio=error1/error2;
        error2=error1;
        if(i!=0)
        {
            cout<<setiosflags(ios::left)<<setw(6)<<intervals[i]
            <<"             "<<setw(7)<<intervals[i]*2+1<<"       "
            <<setw(15)<<error1<<"         "<<setw(10)<<Error_Ratio<<endl;
        }
        else
        {
            cout<<setiosflags(ios::left)<<setw(6)<<intervals[i]
            <<"             "<<setw(7)<<intervals[i]*2+1<<"       "
            <<setw(15)<<error1<<"         "<<endl;
        }
    }
    return 0;

}

Gauss_three.h


int Gauss_three(double x1,double x2)
{
    int i,j;
    double s=0,x;
    double error1,error2=1;
    double Error_Ratio;
    int intervals[9]= {1,2,4,8,16,32,64,128,256};
    cout<<setiosflags(ios::left)<<setw(6)<<"No."<<"             "
    <<setw(7)<<"No.f(x)"<<"       "<<setw(15)<<"Midpoint Rule"
    <<"         "<<setw(10)<<"Error Ratio"<<endl;
    for(i=0; i<9; i++)
    {
        s=0;
        x=fabs(x1-x2)/intervals[i];
        x=x/2;
        for(j=0; j<intervals[i]; j++)
            s=s+x/9*(8*function(2*j*x+x)+5*function(2*j*x+x-sqrt(0.6)*x)
                     +5*function(2*j*x+x+sqrt(0.6)*x));
        error1=s-2;
        Error_Ratio=error1/error2;
        error2=error1;
        if(i!=0)
        {
            cout<<setiosflags(ios::left)<<setw(6)<<intervals[i]
            <<"             "<<setw(7)<<intervals[i]*3<<"       "
            <<setw(15)<<error1<<"         "<<setw(10)<<Error_Ratio<<endl;
        }
        else
        {
            cout<<setiosflags(ios::left)<<setw(6)<<intervals[i]
            <<"             "<<setw(7)<<intervals[i]*3<<"       "
            <<setw(15)<<error1<<"         "<<endl;
        }
    }
    return 0;
}

3、运行情况
Gruss Qusdrature

GrussQusdrature-threepoint

3、  算法效率的比较

         计分方法

         运行效率

trapezium rule

        O(2)

Mid-point rule

            O(3)

Simpson's rule

        O(2)

Gruss Qusdrature

        O(4)

GrussQusdrature-three point

        O(5)

4、 当时小组讨论情况

在第三次的报告中,大家实行两人一组,相互的交流,然后在讨论的时候相互的展示程序。大家百花齐放。之后我们对汇报经行讨论。我们组提出了也尽量做到时间和空间精确读的最优化,大家在课下不仅仅是对课本上的思想在程序经行了实现,而且在实现之后大家相互的交流之后,对算法的时间空间上面进行了优化,在这其中大家试着去做到如何精确,做了许多超出课本上要就的测试,得出为什么越大误差会很大,并且探求出是函数的原因。大家除了课本从算法的优化和对积分的认识上面有了很大的提高。大家积极的参与到后期的报告活动中,很好的完成了后期的汇报工作。

方程微分

1、实际应用

   科学技术中常常要求解常微分方程的定解问题。这里我们着重考察的一阶方程的初值问题

                                               

我们知道,只要函数 适当光滑,譬如关于 满足Lipschitz条件

               。                      (1.3)

理论上就可以保证初值问题(1.1),(1.2)的解 存在并且唯一。实际生产与科研中,除少数简单情况能获得初值问题的初等解外,绝大多数情况下是求不出初等解的。

实用的方法实在计算机上进行数值求解,就是寻求 在一系列离散节点

 

上的近似值 。相邻两个结点的间距 称为步长。如果不特别说明,我们总是假定 为定数,这时节点为       。

初值问题(1.1),(1.2)的数值解法有个基本特点,它们都采用取“步进式”,即求解过程顺着节点的次序一步一步地向前推进,所以只要给出用已知信息 计算 的递推公式。

首先,要对方程(1.1)离散化,建立求数值解的递推公式。一类是计算 时只用到前一点的值 ,称为单步法。另一类是用到 前面 点的值 ,称为步法。其次,要研究公式的局部截断误差和阶,数值解 与精确解 的误差估计及收敛性,还有递推公式的计算稳定性等问题。

    这里我们用了三种数值方法来求解常微分方程组,它们分别是欧拉法、后退欧拉法、Crank-Nicholson方法。

2.主要内容
(1)Euler method
A.算法描述

  在 平面上,我们把微分方程(1.1)的解 称作它的积分曲线。积分曲线上一点 的切线斜率等于函数 的值,如果按函数 在 平面上建立一个方向场,那么,积分曲线上每一点的切线方向均与方向场在该点的方向相一致。

基于上述几何解释,我们从初始点 出发,先依方向场在该点的方向推进到 上一点 ,然后再从 依方向场的方向推进到 上一点 ,循此前进推出一条折线 (图9.1)。

一般地,设已做出该折线的顶点 ,过 依方向场的方向再推进到 ,显然两个顶点 , 的坐标有关系

 

                                              (2.1)

这就是著名的欧拉(Euler)公式。若初值 已知,则依公式(2.1)可逐步算出

                        

   B.代码实现

          测试例子:        

          易解得其原函数是

 初始化:t=0.0,y=1.0,dx=0.1;

主要通过迭代来完成

   for(i=1; i<=10; i++)

    {

        t=(i-1)*dx;

        y=y+dx*fun(t,y);

        Y=funr(t);

        Error[i]=Y-y;

        if(i==1) printf("%d\t        %.10f\t    %.10f\t    \n",i,y,Error[i]);

        if(i>1) printf("%d\t        %.10f\t    %.10f\t%.10f \n",i,y,Error[i],Error[i]/Error[i-1]);

}

C.运行结果

     运行环境:VC++6.0

(2)Backward Euler
A.算法描述

假设 ,即顶点 落在积分曲线 上,那么,按欧拉方法做出的折线 便是 过点 的切线,从图形上看,这样定出的顶点 明显地偏离了原来的积分曲线,可见欧拉方法是相当粗糙的。

为了分析计算公式的精度,通常可用泰勒展开将 在 处展开,则有

          (2.2)

在 的前提下, ,于是可得到欧拉法(2.1)的公式误差

                                (2.3)

称为此方法的局部截断误差

如果对方程(1.1)从 到 积分,得

.      (2.4)

右端积分用左矩形公式 近似,再以 代替 , 代替 也得到(2.1),局部截断误差也是(2.3).

如果在(2.4)中右端积分用右矩形公式 近似,则得另一个公式

,        (2.5)

称为后退的欧拉法

B.代码实现

for(i=1; i<=10; i++)

    {

        t=i*dx;

        y=y+dx*fun(t,y);

        Y=funr(t);

        Error[i]=Y-y;

        if(i==1)  printf("%d\t        %.10f\t    %.10f\t    \n",i,y,Error[i]);

        if(i>1) printf("%d\t        %.10f\t    %.10f\t%.10f \n",i,y,Error[i],Error[i]/Error[i-1]);

     }

C.运行结果

     运行环境:VC++6.0

 

(3)Crank-Nicholson

     A.算法描述

    为得到比欧拉法精度高的计算公式,在等式(1.4)右端积分中若用梯形求积公式近似,并用 代替 , 代替 ,则得

                             (2.7)

称为梯形方法.

梯形方法是隐式单步法,可用迭代法求解.同后退的欧拉方法一样,仍用欧拉方法提供迭代初值,则梯形法的迭代公式为

      (2.8)

为了分析迭代过程的收敛性,将(2.7)式与(2.8)相减,得

 

于是有

式中 为 对 满足Lipschitz常数,如果选取 充分小,使得

则当 时有 ,这说明迭代过程(2.8)是收敛的.

B.代码实现

  for(i=1; i<=10; i++)

    {

        t=i*dx;

        tem=y;

        y=y+dx*fun(t,y);

        y=tem+(dx*fun(t,y)+dx*fun((i-1)*dx,tem))/2.0;

        Y=funr(t);

        Error[i]=Y-y;

        if(i==1)   printf("%d\t        %.10f\t    %.10f\t    \n",i,y,Error[i]);

        if(i>1) printf("%d\t        %.10f\t    %.10f\t%.10f \n",i,y,Error[i],Error[i]/Error[i-1]);

}

 

C.运行结果

 

这里,我们还有介绍一种改进的欧拉方法:

显示欧拉公式计算工作量小,但精度低。Crank-Nicholson方法虽提高了精度,但为隐式公式,需用迭代法求解,计算工作量大。综合两者便可改进Euler公式。 先用Euler公式求出一个初步的近似值 ,称为预测值,它的精度不高,再用Crank-Nicholson公式对它校正一次,即迭代一次,求得 ,称为校正值。即得到改进的Euler公式:

 

可以证明该公式的精度是二阶,这是一种显示方式

相应具体代码如下:

    for(i=1; i<=10; i++)

    {

        t1=(i-1)*dx;

        t2=i*dx;

        tem=y+dx*fun(t1,y);

        y=y+(dx*fun(t1,y)+dx*fun(t2,tem))/2.0;

        Y=funr(t2);

        Error[i]=Y-y;

        if(i==1)     printf("%d\t        %.10f\t    %.10f\t    \n",i,y,Error[i]);

        if(i>1) printf("%d\t        %.10f\t    %.10f\t%.10f \n",i,y,Error[i],Error[i]/Error[i-1]);

 }

以下是运行结果:

 

可以从运行结果看出,结合改进后的欧拉法后误差相对变小,精确度和稳定性相对高于前面的显示欧拉法。

 

3、算法效率的比较

各种算法的优劣比较:

        方法

        优点

        缺点

    Euler Method

        简单

       精度低

  Backward Euler

      稳定性好

  精度低,计算量大

    Crank-Nicholson

      精度提高

       计算量大

 

各种算法局部截断误差和阶数的比较:

                                                                   (h代表步长)

        方法

       截断误差

       阶数

    Euler Method

      

       一阶

  Backward Euler

   

       一阶

    Crank-Nicholson

      

       二阶

 

经探讨,我们得出提高计算精度的方法

①增加展开项数。

  增加 函数的泰勒展开式的阶数,即逐次取高次项,这样就可以减少截断误差。其误差系列为

②缩小步长

  由于差分间隔减小,即h值变得很小,可使计算精度提高。在理论上步长值越小越好,而且趋近于0最好。但是,dx越小会使计算次数增加,浪费计算时间,而且还会使舍入误差增大。

 

4、小组内讨论情况

     ①大家对算法经行了细致的研究

     经过上三次的编写程序之后我们对各自的编程的特点和基本思路有了一个清晰的了解,大家在交流的时候也是明显的速度加快了许多,同时对微分的认识也是加强了很多。对于这次的编程我们组提出了也尽量做到时间和空间也精确读的最优化。于是大家在课下不仅仅是对课本上的思想在程序经行了实现,而且大家试着去做到如何精确,做了许多超出课本上要就的测试,得出为什么越大误算从而更加精确的确定其微分的值。大家除了课本从算法的优化和对积分的认识上面有了很大的提高。

     ②大家积极的参与到后期的报告活动中

    这次中,大家表现出前所未有的热情,争先恐后的去做报告PPT等任务,力求做的最好。在即上三次的分工之后,我们这次决定再次相互的交换一下工作。我们最终的程序或许没有解决我们最初讨论出的问题,但是我想大家参与了就是一种最大的收获。这次的分工是:陈俊桦、韩学武、肖大军和梅旭由四位同学负责修改程序,王艳琴和向胜男经行程序的测试和算法的描述工作,彭亚琼、刘宇、方正写word文档,肖大军和梅旭负责制作PPT ,张钟文和杨耀鹏写台上的细化工作。

五、结课感言

小组总结

经过一学期的学习,从小组的角度看,小组有了一个不错的成长。小组阿紫组织大家的学习讨论的时候,本着老师要求的基本原则,经行了多次的改革。首先介绍一下组内的成员。我们小组内的成员相对其他组来说没有编程能力特别出众的人员,所以我们小组在第一次的实习中经行了一次小小的尝试,结果很显然,写出程序来的人并不多,有的甚至连教材上面讲的基本原理都不清楚,所以在第一次讨论之后,我们组内经行了一次关于改革的讨论,将大家分为两人一组,这样可以加强大家之间的交流,同时也能让大家都参与到其中,第一次的报告其实完成的还是很仓促的。但是第二次的时候就是有了一个新的面貌,两人一组经行汇报讨论,这样大家就建立在讨论之前两人已经进行了交流,这样进度经快了很多,完成之后我们现场对一些精度等存在问题的代码现场经行了更改,这样让大家更清楚了在写程序的时候需要注意什么。然后我们开始对组间汇报有了一个明确的分工。在组间汇报完之后,我们并且对每个组的汇报经行了总结,对第三次的汇报提出要求,希望大家不仅仅以实现算法,尽量的让代码从时间空间可读性等各个方面有一定的建树。等到第三次实习的时候,大家对原理和代码都很熟悉,讨论很快就结束了,我们这次着重的经行了一下对每个人写代码的特点的展示,比如如何考虑和实现时空的最优化,如何让代码健壮性更好,有的人更是展示了面向对象的实现方式。大家在相互交流的同时相互的学习,使自己在编程的思想上面有了一定的提高。这次大家很积极的要求去做各个任务。在这个基础上面我们经行三次汇报结束之后,就各个小组之间存在问题经行了探讨。于是在第四次汇报的时候我们不仅仅是对教材上面的微分的内容经行了实现,还对一些大家忽略的内容比如各个类型的精确度问题等经行了探究,让我们对实现中各个实现过程更加的胸有成竹。

可能我们组做的不是做好的,但是从一定程度上说我们觉得我们已经得到自己想要得到的,不仅仅是在计算方法上面更是在大家对编程的自信心和技巧上面有了一个很大的提高。有句话说的好:我们不和其他人比较,我们每次超越自己一点剧足够了。的确在这个学期的学习中,我们小组虽然没有那么辉煌的成就,但是我们对每一个组员都是热心的帮助,大家一起进步,让很多以前没有动手编过程序的人开始意识到编程没有自己想象的那么难。

在课程即将结束的时候,有组员主动的提出要去完成某些任务,当这次任务已经那排好了的时候,他要求下次让他来。这和其他组的本着能者多劳的原则大大的不同,在我们组这样的人不仅仅一个,而是大家一起。虽然有些事情说出来没什么骄傲的,但是我依然觉得自始至终在老师不点名的情况下,我们组内的成员没有一个人翘过一节课,更是后来似乎爱上了这种模式。这源自于大家对小组的付出和在小组内的存在感。我想在大学的学习中,本次的小组学习是大家经历过的醉成功学习之一。

为什么大家积极的去做任务,因为大家对小组爱的深沉。

小组成员感言

组长 韩学武

    作为组长在这学期的计算方法学习上面有很大的收获很大,在四次的实习中,积极的完成每次的程序编写工作,然后积极和大家讨论,并且积极的组织大家经行小组简单扼汇报准备工作,每次的汇报主要分担了写报告的工作。除此之外还积极的对小组的管理和安排经行改革极大的调动大家的积极性。通过此次计算方法的学习,我最大的感受就是团队精神,俗话说“三人行必有我师”在多次的交流之后,在编程思想,PPT制作,汇报方式等等方面学到了很多。在这种积极活跃的授课方式之下,感觉到对计算方法和程序编写有了更深的认识。

向胜男

起初,我对老师用英文版教材授课的方式很不习惯。由于英语水平有限,课本上内容基本看不懂,单靠听老师的讲解只能半知半解。后来老师又要求对每章节的知识用程序实现,而且进行讨论并作汇报,这让我开始对这门课程感到些许的茫然。但是,为了真正弄懂各种算法的原理,我课后还是积极查阅资料,尝试着编写出正确的程序。有一次程序运行结果不对,自己花了大量时间还是不知道问题出在哪里,后来在小组讨论环节经和同学分析将问题解决。虽然那次程序写得粗糙,但还是很有成就感,并且渐渐对老师的这种授课方式提起兴趣来。

四次程序汇报后,这门课也就相应结束了。在这过程中,我感受到了团队合作的重要性。每次小组汇报,和大家一起交流算法,提出并分析问题,接着准备汇报材料,在有限的时间内大家一起忙碌各自分配的任务,喜欢这样一个愉快的过程。同时,发现自己的动手实践能力也提高了,学会如何调试修改程序,完善自己的代码,以及美化输出界面等,而且对知识原理了解得更加透彻了。当然,拿起英文教材也没那么恐惧了,认识了不少单词呢。如果我们平时没有这样的练习,最后知识传统地笔试考试后就结课是完全达不到这种效果的。

肖大军

   诚然的说以前从来没有老师以这种方式授过课。我能感受的到,我不仅仅学习到了课本上的知识,更提高了团队合作,有效沟通,当众演说等其他方面的综合素质。

首先,上课的教材采用英文版本就让我们耳目一新,诚然以我个人的英语水平还不能完全理解教材。经过在课堂上老师的重点剖析,能理解计算方法的基本算法思想,并能独立的编写每一个程序。英语教材的使用也让我再次意识到英语水平的不足,以及英语学习的重要性和迫切性。

然后老师采取分组的方式进行交流,的确很契合大多数场合集体交流探讨的需要,让我们意识到团队的重要性,对今后我们的工作实践有了较好的启蒙基础,在小组内积极讨论还锻炼了我们的团队协作能力,增进了大家的情感交流,学习了不同同学好的算法思路。

采取小组回报的方式,给我们提供了一个上台发言的平台,让我们尝试着在更多人面前讲话,做PPT展示,克服胆怯的心里,锻炼了交际能力,灵活的应变能力,对今后的学习工作都有启蒙意义。

总的来说,在计算方法这门课上,我学到的东西着实很多,在上课时,积极围绕着老师的讲解思考问题,有时老师一些发人肺腑的话,也让人受益匪浅;课下我积极编程实现算法,提高了动手能力,也进一步的理解了算法的核心思想;在小组内讨论时,积极帮同学解决困惑,积极思考同学提出的新的算法思路,这些都让我受益匪浅;经过全组同学的共同努力,在小组汇报时,我抱着锻炼自己的心态积极参加小组汇报!

彭亚琼

说起计算方法,先谈谈计算方法的授课老师-曾老师吧,第一次上曾老师的课,给我的感觉就是老师的态度非常认真,为了让多数同学能听懂,很基础的定理、公式都在黑板上一一推导,还时不时的找同学提问,以确定同学是否真正听懂。此外,在英语不怎么好的情况下,曾老师坚持用英文教材,目的在于督促大家学习更多的英语,促进英语能力的提高。而我的收获也是非常大的,首先是英语专业词汇的学习,在讲解每一章内容时,我都会用手机查询不懂的词汇,并且掌握;再者就是掌握了一系列解决实际问题的方法,主要学习对象是微分方程,常微分方程,线性方程组,学习了迭代法、二分法、插值法的理论知识,并在计算机上用所学内容实现了对相关问题的求解,掌握了微积分线性代数,常微分方程中的数学问题,并学习了误差、收敛度的分析与判断。此外掌握了一种重要的数学思想-离散化:离散化是程序设计中一个很常用的技巧,它可以有效的降低时间复杂度。在学习数值积分时,Trapezium rule、Mid-point rule、Simpson’s rule、Gauss quadrature等方法都体现了离散化的思想,降低了解决实际问题过程中的难度;最后就是提升了我的团队合作能力,这也是老师一直强调的东西,要有集体荣辱观,这样才能发挥你个人的最大潜质,为小组贡献自己的力量。并且学习态度也有了改善,在学习一门新的学科时,不能凭自己的喜好决定你的努力程度,你要对自己负责,学东西时一定要持有认真的态度,不能随心所欲。本门课程学习过程中收获颇丰,希望自己秉着学习的态度一直走下去。

杨耀鹏

其实一直以来感觉自己在数学方面还是比较感兴趣的,但是从学完线性代数和高数后自己也就很少去碰数学方面的书了,直到这个学期的这门计算方法让我重新又找回了学习数学的感觉。经过这一个学期的学习,总体感觉还行,基本上都能领悟。个别的知识点可能比较抽象,但是好多的算法我们都经过了上机实践,所以掌握起来会更透彻一点。学习了这门课,感觉实用性比较大。像拉格朗日和牛顿插值法等等算法。因为我们在现实生活中需要通过已有的数据来发掘事物本身的内在规律,或者模拟出相应的数学模型来解决。所以这就需要我们用到这学期学习的相关知识来完成。这门课程也是连接数学与计算机之间的桥梁,之前学习的数学积分的知识现在也知道怎么用程序来实现了。还有就是对线性方程组和非线性方程组的求解方法的掌握。插值的应用自己还想说的就是。自己准备和同学一起做关于图像处理的方面的东西,所以当时我就觉得这门课程作用不一般。学完了这门课程也希望自己活学活用,发挥这门课应有的作用。

方正

  经过了这个学期对计算方法的学习,总体感觉还行,跟着老师的节奏,积极参加小组活动,课后仔细研究老师推荐的剑桥数值方法教材,基本上都能领悟,除了个别知识点可能比较抽象外,但是好多的算法我们都经过了上机实践,所以掌握起来会更透彻一点。学习了这门课程后,我感觉实用性很大,因为在我们现实生活中我们经常需要通过已有数据来发掘事物本身的内在规律,或者模拟出相应的数学模型来解决,这就需要我们用到这学期学到的相关知识来完成了。这门课程也是连接数学与计算机之间的桥梁。其实学习这门课最大的收获是老师让我们懂得了团队合作的意义,不仅培养我们的合作意识、团队精神、理性思考、同时也提升我们的境界拓宽我们的胸怀,尺有所短寸有所长,要多发现和挖掘各自的优势和长处,求知的过程要提倡个人资源互补、优势共享才能少走弯路,携手共赢。我很喜欢也很欣赏曾三友老师的这种富有创新意义的教学模式,让我受益匪浅,得到了很大的提高。谢谢!

梅旭

在计算方法的课程学习中,曾老师的教学方法明显和一般老师的不同,不仅仅是让学生学习理论的知识,还将理论与实践紧密的结合起来,以此提高学生的动手能力。星期二课堂上的讨论更是让学生对理论知识有了更深的理解,而星期四的汇报也让每个人有机会学习其他人的程序和汇报形式。不过这门课程对英语水平有较高的要求,也许是英文教材写得更好或者是有意让学生了解数学术语的英文书写、提高英语阅读水平,我还是觉得用中文教材更方便学生学习。

王艳琴

课程设计是培养学生综合运用所学知识,发现,提出,分析和解决实际问题,锻炼实践能力的重要环节,是对学生实际工作能力的具体训练和考察过程.随着科学技术发展的日新日异,程序软件已经成为当今计算机应用中空前活跃的领域, 在生活领域中的应用可以说得是无处不在。因此作为二十一世纪的大学来说掌握简单的软件的开发技术是十分重要的。      回顾起此次数值分析的课程设计,至今我仍感慨颇多,的确,从选题到定稿,从理论到实践,可以说得是苦多于甜,但是可以学到很多很多的的东西,同时不仅可以巩固了以前所学过的知识,而且学到了很多在书本上所没有学到过的知识。通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独立思考的能力。在设计的过程中遇到问题,可以说得是困难重重,难免会遇到过各种各样的问题,同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固,通过这次课程设计之后,一定把以前所学过的知识重新温故。  我得到了很多同学的帮助。我想没有他们我可能都要放弃了,因为我本人对数值分析的算法本来就不是很熟悉,学的东西也不能很好的灵活应用,理论联系不了实际。

通过这段时间的学习,我认为要学好C++程序这门课程,不仅要认真阅读课本知识,更重要的是要通过上机实践才能增强和巩固我的知识。特别是作为大学生,更要注重实践这一环节,只有这样我们才能成为合格的计算机人材。  整个过程不断的调试,在调用子程序的时候遇到了部分问题,最后幸好都解决了。通过这次课程设计也稳固了一些已经学习的数值分析的算法,同时了解了一些以前没有接触的数值分析的算法。总之,这次的课程设计受益匪浅。

张钟文

通过对计算方法的学习,让我明白了两个道理。一、做一件事要做好充分的准备,那样便可以事半功倍。在正式操作前,对理论知识的学习很重要,经过听老师讲课、课后自己看书,我对这门课的理论知识有了一定了解。二、学习中要勇于创新,不能墨守陈规。在编程时,我发现有时候一个题目在用常规方法完成后,我们可以通过一些改进,从而可以让程序变得更加简明易懂,这就需要我们的创新精神。

在上机实践中,最具有挑战性的是编程,它需要扎实的C语言功底和较强的逻辑思维能力及一定的编程技巧。正好让我对已经学习过的C语言这门课程进行复习与巩固,真是一举两得。
    经过这几天学习的实践,我已经对数值计算方法这门课程有了一定的了解,我相信有了这样实用的数学工具,在今后的学习生活中一定会给我带来狠多的帮助,我也会更加努力,争取更大的进步!!!
    此外,在本次上机训练的学习中体验到了团队的重要性,大家分工合作,会把事情简单而又有效的完成。

陈俊桦

计算方法是信息科学与计算科学紧密相联的一门课程,与计算机科学有着相辅相成的作用。一来计算方法的理论可以为计算机编程提供算法理论;另一方面,通过编程实现,也可以对计算方法的算法效率和实现效果进行衡量和比较。作为一名计算机专业的学生,仅仅知道计算方法的理论知识显然还是不够的,还要知道如何将算法编程实现。

  不同于之前的计算方法课程,这次的课程老师更加注重了对动手编程能力的考查,而不是对理论知识的考核。对于我们专业的同学来说,这样的考查形式更有意义,也更符合我们锻炼和提高编程能力的要求。通过这样一门实践性较强的课程的学习,自己还是有所收获的。

  四次编程实践真正的锻炼了我思考问题和动手编程的能力。比如,在用LU分解法求解线性方程组的时候,会有三个矩阵需要存储:系数矩阵,系数矩阵的下三角矩阵和系数矩阵的上三角矩阵。如果为每个矩阵都单独开辟存储空间,无疑将会占用太多的资源,所以可以用为系数矩阵开辟的空间来轮流存储这三个矩阵,这是在课堂上我所学到的一个如何更好的解决问题的一个方法。自己动手编程的重要在于通过自己去编写代码,才会发现问题,然后想出解决问题的办法,使自己的编程能力得到提高。

这次以小组形式进行编程实践对我们团队合作意识的培养液起到了很大的作用。一个人想到的问题和解决方法是有限的,这也是为什么团队合作精神对于程序编写人员来说如此重要的原因。在一个小组里面,和同学们一起针对给出的算法进行讨论,各抒己见,彼此之间分享自己的想法,最终每个小组成员都能吸收到别人的好的方法,同时也可以让自己的好的方法为他人所用。这样的一个环境让我受益匪浅,知道了如何更好地和他人交流,通过团队合作来完成程序的设计。

  总之,以动手实践编程为考查方式的计算方法课程的学习,对于计算机专业的我们,还是有比较大的帮助的。在平时训练量少的情况下,这门课程的编程实践也成为了比较难得的锻炼的机会。理论知识固然重要,但是更要将理论知识运用到实践中,那样才能学以致用,达到我们学习的更进一步的目标。

刘宇

我是信息工程学院的学生,是为了学习算法设计而选择的这门课。

在这门课上,我们主要学会了泰勒公式在计算机数据在算法设计中的应用。我们进行了求函数值(二分法、Newton-Raphson、迭代法),线性方程求解(高斯消元法、LU算法),求积分(梯形法、

Mid-point rule、Simpson's rule、Guass quadrature),求解常微分方程(Euler method、backward Euler、Crank-Nicholson、Multistep methods)等方法的实验。

利用泰勒公式进行计算方法的学习好处是用函数值替代导数,简化程序设计的算法,缩短计算时间,此方法在工程领域的应用异常广泛。

而这门课程锻炼的不仅仅是我们的编程能力和数学能力,因为我们每次都要进行PPT的讲解,我们还锻炼了算法论文的写作能力和讲解能力。

通过这门课,我学到了很多东西,不枉费我选择了这门课程。

六、小组分工

第一次实习:

成员

报告中的任务

成员

报告中的任务

韩学武

整理文档

方正

比较程序优劣

彭亚妹

制作PPT

肖大军

讲解PPT

梅旭

修改程序

刘宇

对算法效率测试

陈俊桦

对算法效率测试

杨耀鹏

修改程序

张钟文

修改程序

向胜男

整理文档

王艳琴

制作PPT

第二次实习

成员

报告中的任务

成员

报告中的任务

韩学武

修改程序

方正

修改程序

彭亚妹

修改程序

肖大军

汇报

梅旭

制作PPT

刘宇

修改程序

陈俊桦

修改程序

杨耀鹏

写文档

张钟文

写文档

向胜男

制作PPT

王艳琴

细化台上汇报

第三次实习

成员

报告中的任务

成员

报告中的任务

韩学武

写文档

方正

了解关于课外的积分方法

彭亚妹

细化台上细节

肖大军

上台展示

梅旭

了解关于课外的积分方法

刘宇

制作PPT

陈俊桦

制作PPT

杨耀鹏

修改程序

张钟文

修改程序

向胜男

写文档

王艳琴

分析其他组的代码特点

第四次实习

成员

报告中的任务

成员

报告中的任务

韩学武

修改程序

方正

写word文档

彭亚妹

写word文档

肖大军

制作PPT

梅旭

修改程序

刘宇

修改程序

陈俊桦

修改代码

杨耀鹏

细化台上工作

张钟文

制作PPT

向胜男

算法描述

王艳琴

程序测试

总报告

成员

报告中任务

页数

成员

报告中任务

页数

韩学武

撰写主要内容、目录、小组感想、总结、最后整理工作

1~2、4、46~47、51~54

方正

撰写前言

3

彭亚妹

撰写计算方法概要

5~6

肖大军

撰写解方程部分

6~12

梅旭

撰写解方程部分

6~12

刘宇

撰写求解方程组部分

12~23

陈俊桦

撰写求解方程组部分

12~23

杨耀鹏

撰写求解积分部分

23~39

张钟文

撰写求解积分部分

23~39

向胜男

撰写求解微分部分

39~46

王艳琴

撰写求解微分部分

39~46

注:我们每次实习都会写好报告和PPT所以最后报告各个实习内容的撰写相对比较容易

七、总结

通过这次与众不同的计算方法课程的学习,我们在此间都收获了很多。从我们小组的角度将从以下几点谈论对这个学期计算方法学习做一个总结。

 1、首先从学习收获的角度。从组内人们的交流过程中我们可以得到几点。首先,大家对计算有了一个新的理解。以前大家学习高数的时候整天研究做题,但是对高数中的积分微分等方法的原理没有一个基础的理解。但是这次,我们组的成员能深刻的理解到计算的基本原理,这样对知识的掌握有一个新的高度。其次,除了计算原理理解之外,大家在计算方法的学习和编程实现中也渐渐的明白了一个理论的公式计算(如同高数中复杂的公式,高难度的运算)如何转化成程序去实现。在这个过程中,大家明白了计算机运行,或者说是设计一个算法的基础是什么,简单的说是借用计算机告诉可重复的运算来弥补其中其离散的缺点。这样虽然不能带到醉精确的数值但是可以得到一个你需要的数值。在这个过程中我们从教材上,从课堂上去体会是怎么把一个问题去离散化,如何去用迭代等方式去逼近一个问题等等。通过学习我们基本上认识到了怎么将一个现实的问题去用编程思想去考虑。这不仅仅体现在我们队算法的理解上面,更是我们对编程的一次新的理解。

2、其次从授课方式角度。曾老师改变以前的授课和考核方式,以小组的方式经行考核,这样对我们来说也是一个挑战。但是从最终大家的结果来看收获颇丰。第一、让大家对教材的知识有了一个全新的认识。采用阶段性的小组汇报,这样让大家有时间经行讨论,在大家写程序的时候对教材的知识有了一遍了解,在给大家讲解的时候有了一个更深的了解,然后到最后的报告总结,当大家能用自己的话把课本上的很多东西写出来的时候,或许大家不仅仅是看了教材上的内容,还会参考很多课外的资料,我想这个时候他们的理解会是非常深刻的。

第二、培养了大家的团队合作能力,在这学期的计算方法的学习中,我们组从写程序到最后的报告总结始终贯彻着团队的精神,在写程序初期,我们组织两人一组,相互的补充相互的学习,使得周二的讨论效率更高,在讨论好大家之后,大家的分工明确在完成自己的工作得到同时主动帮助其他人完成任务。于此同时大家相互的交换工作相互的知道让每个人有了很快的成长。大家在团队中清楚了自己的角色,如何把一个比较大的工程分解到每个人身上,再怎么整合起来成为一个需要的产品。这不仅仅在这次的学习中很重要,也渐渐的明白了团队的工作。第三、大家热情高涨,收获效率更上一层楼,像其他的组一样,开始的时候我们组也是存在部分 同学基础比较差编程能力相对来说比较弱,我们在按照老师的授课方式的基础上,在小组内实行两人一组等一系列的活动安排,调动大家的热情,渐渐的大家开始积极的展示自己的代码,对讨论的后的安排工作大家开始抢着做,一度出现了预约下一次任务的场景。虽然大家做任务的水平参差不齐,但是还是本着大家自愿保留大家成果的原则经行每一次的小组汇报。这样可能每次报告不是最好的,但是极大的调动了大家的积极性,这样大家的收获肯定是最高的。

原文地址:https://www.cnblogs.com/XDJjy/p/3119467.html