模块化程序设计——例程和模块ppt课件_第1页
模块化程序设计——例程和模块ppt课件_第2页
模块化程序设计——例程和模块ppt课件_第3页
模块化程序设计——例程和模块ppt课件_第4页
模块化程序设计——例程和模块ppt课件_第5页
已阅读5页,还剩36页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

.,1,第3章模块化程序设计例程和模块,“模块”直接映射为例程:子程序和函数内部例程和外部例程程序构造单元:主程序(包含有内部例程)、模块(包含有内部例程)、外部例程(单独的,包含有内部例程),.,2,第一节内部例程,一内部函数1.构造形式实例牛顿法求解方程:方程的一般形式为设根的一个近似值为,新的近似值为:其中:是的一阶导数,通过叠代的方法获得近似解,满足。假设f(x)=x3+x-3,那么f(x)=3x2+1;根的初值设为2;叠代控制条件为f(x)10-6,或者叠代步数不超过20;用F(x)代表f(x),用DF(x)代表f(x)。,.,3,例3-1牛顿法解方程PROGRAMNewtonIMPLICITNONEINTEGER:Its=0!叠代数INTEGER:MaxIts=20!最大叠代数LOGICAL:Converged=.false.!是否收敛REAL:Eps=1e-6!叠代精度REAL:X=2!根的初值DOWHILE(.NOT.Converged.AND.ItsMaxIts)X=XF(X)/DF(X)PRINT*,X,F(X)Its=Its+1Converged=ABS(F(X)N,不执行DO循环(Fact=1),当函数Fact返回到主程序打印时,I的值为2;下一次引用时,I在主程序DO循环中增至3,依次类推正确方式是在内部函数中重新声明I为局部变量。例如:INTEGERI在内部例程中声明所有变量应成为一条编程规则,以消除全局变量带来的负面影响。共享数据,声明变量模块。,.,9,3.函数返回值Fortran中,表达式(函数)值一是通过函数名赋值来实现,例如:F=X*3+X-3此时赋值号左边的函数名不能带参数表。另一是通过RESULT子句来实现,例如:FUNCTIONF(X)RESULT(R)REALR,XR=X*3+X-3ENDFUNCTIONF其中,R代表函数结果,其数据类型代表函数类型;赋值号左边不再是函数名F,而是函数结果R,相应的函数类型声明,也由声明函数名F改为声明函数结果R。,.,10,4.语句函数Fortran90也支持Fortran77提供的语句函数,不推荐。例3-3语句函数的使用PROGRAMStatement_FunctionIMPLICITNONEREALf,x,y!函数名f、形参x、实参y均需声明类型f(x)=x*2/SQRT(1.0+2.0*x+x*2)!定义语句函数DOWRITE(*,(A),ADVANCE=NO)输入x的值:READ*,yIF(INT(y)=0)EXIT!0终止循环PRINT*,f(,y,)=,f(y)ENDDOENDPROGRAMStatement_Function,.,11,语句函数的形式为:函数名(参数1,参数2,)=函数表达式语句函数在形式上和数学上的函数表达式完全一样,语句函数使用时应注意以下几点:(1)语句函数先定义后使用,且只能用一条语句来定义;(2)定义语句应放在声明部分,且放在语句函数相关的类型声明之后;(3)参数列表可以为空(此时,函数实际上是一常量表达式),但函数名后边的一对括号,无论在定义还是引用时都不能省略。,.,12,二内部子程序内部子程序和内部函数主要差别在于:(1)没有返回值和子程序名关联,因此无需声明子程序类型;(2)通过CALL语句调用子程序;(3)在例程原型(头)和END语句(尾)中,使用关键字SUBROUTINE;(4)若子程序参数表为空,子程序名后的一对括号可以省略;(5)函数通过函数名返回一个值,子程序通过函数参数可以返回多个值。,.,13,例3-4内部子程序用来实现2个数据的返回(交换)PROGRAMExchangeIMPLICITNONEREAL:A=1,B=5CALLSwop(A,B)PRINT*,A,BCONTAINSSUBROUTINESwop(X,Y)REALTemp,X,YTemp=XX=YY=TempENDSUBROUTINEENDPROGRAM,.,14,程序说明:Fortran参数传递,缺省为引用传递(地址传递);子程序调用时,实参A、B的值被传递给参数X、Y,改变后的形参值被返回调用程序,实现两个数据的交换;子程序中的Temp为局部变量,在主程序中不可访问;如果希望参数以数值方式传递,这样形参的改变不影响实参,为此Fortran90提供了INTENT属性。内部子程序的构造形式:SUBROUTINE子程序名(参数表)声明语句执行语句ENDSUBROUTINE子程序名,.,15,主程序构造形式:PROGRAM程序名声明语句执行语句CONTAINS内部例程ENDPROGRAM程序名注意事项:(1)一个完整的程序有且只有一个主程序;(2)主程序只有END语句是必须的,其他都是可选的;(3)若含有内部例程,必须出现关键字CONTAINS;(4)可以有多个内部例程,但内部例程不能再含有自己的内部例程,不允许内部例程的嵌套;(5)END语句若出现程序名,其前面的PROGRAM关键字不能少。,第二节主程序,.,16,构造形式:SUBROUTINE子程序名(参数表)声明语句执行语句CONTAINS内部例程ENDSUBROUTINE子程序名或者FUNCTION函数名(参数表)声明语句执行语句CONTAINS内部例程ENDFUNCTION函数名外部例程和内部例程的比较:(1)外部例程是单独的外部文件,除头、尾外,形式上与主程序是相同的;(2)外部例程可以含有内部例程,而内部例程不能再含有内部例程;(3)END语句中的关键字FUNCTION/SUBROUTINE,在外部例程中是可选的,但在内部例程中是必须的。,第三节外部例程,.,17,例3-5采用外部例程实现Swop(交换)PROGRAMExchangeIMPLICITNONEEXTERNALSwop!声明例程Swop为外部的REAL:A=1,B=5CALLSwop(A,B)PRINT*,A,BENDPROGRAMExchangeSUBROUTINESwop(X,Y)REALTemp,X,YTemp=XX=YY=TempENDSUBROUTINESwop若外部程序名与系统的标准例程名相同,编辑器会优先引用标准例程,而不是用户定义的外部例程;为避免出现这种情况,可在调用例程的声明部分,添加外部例程声明语句(EXTERNAL),这应该成为一个编程惯例。,.,18,例程接口:包括例程名、参数个数及各自的数据类型等信息。分为:显式接口(对标准例程、内部例程和模块例程)和隐式接口(对外部例程)。Fortran90提供接口块,以向调用程序明确外部例程的接口信息。接口块构造形式:INTERFACE接口体ENDINTERFACE接口体由外部例程头、参数声明和外部例程尾构成。参数名可以和外部例程定义用的参数名不同,也可以相同(将外部例程定义的参数声明部分直接拷贝)。,第四节接口块,.,19,例3-6在主程序中添加接口块,实现Swop外部例程PROGRAMExchangeIMPLICITNONEINTERFACESUBROUTINESwop(X,Y)REALTemp,X,YENDSUBROUTINESwopENDINTERFACEREAL:A=1,B=5CALLSwop(A,B)PRINT*,A,BENDPROGRAMExchange在程序中不需要用EXTERNAL语句声明外部例程。,.,20,必须使用接口块的情况:(1)外部例程具有可选参数;(2)例程用来定义操作符重载;(3)外部函数返回数组或变长字符串;(4)外部例程具有假定形状数组,指针或目标参数;(5)例程作参数;(6)例程重载。除了操作符和例程重载外,其他的只要将外部例程转化为模块例程,就可以免去提供接口块的麻烦,模块在Fortran90中具有十分重要的作用。,.,21,1构造形式Fortran90有三种程序单元:主程序、外部例程和模块,模块主要是用来在程序单元之间共享数据和操作例程。其构造形式如下:MODULE模块名声明语句CONTAINS模块例程ENDMODULE模块名,第五节模块,.,22,例3-7模块使用MODULEMyUtilsREAL,PARAMETER:PI=3.1415927CONTAINSSUBROUTINESwop(X,Y)REALTemp,X,YTemp=XX=YY=TempENDSUBROUTINESwopENDMODULEMyUtils!模块和主程序在同一文件中,模块在主程序之前PROGRAMMainUSEMyUtils!位于IMPLICITNONE、声明语句之前IMPLICITNONEREAL:A=PI,B=PI*2CALLSwop(A,B)PRINT*,A,BENDPROGRAMMain,其中:例程Swop被转换为模块例程,主程序通过引用(USE)模块,使用其中的模块例程及数据。,.,23,模块例程作为模块的内部例程,其形式和主程序,外部例程包含的内部例程是一样的,只不过模块例程还可以包含自己的内部例程。模块、主程序、模块例程、内部例程和外部例程的关系如下:其中:Mod-sub指模块例程,Int-subs指内部例程,Ext-sub指外部例程。,Module,Mod-sub,Int-subs,Ext-sub,Int-subs,Mainprogram,Int-subs,Ext-sub,Int-subs,Module,.,24,Fortran90中,数据块程序单元被模块程序单元替代;模块不仅可供主程序和外部例程引用,还可供其他模块引用;主程序、模块、外部例程之间的关系如下图所示:,ProgramA1,UsemoduleA,ModuleA,Contains,Modulesubroutineoffunotion,SubroutineB,Externalsubroutine,CallB,Contains,EndProgramA1,Internalsubroutineoffunotion,主程序、模块、外部例程之间的关系,.,25,2USE语句模块的引用,一般形式为:USE模块名模块的引用,其他形式为:(1)不方便直接使用模块实体名,可在程序中重新命名,引用形式为:USE模块名,重命名列表(新实体名=原实体名)例如:模块YourMod有一个例程或者变量YourPlonk,被重新命名为MyPlonk:USEYourMod,MyPlonk=YourPlonk(2)程序只使用模块中的部分实体,采用如下的引用形式:USEYourMod,ONLY:X,Y这表示只使用模块YourMod中的X和Y,冒号后边的实体可被重命名。(3)假如要同时引用多个模块,每个模块都要使用单独的USE语句,并使USE语句出现在IMPLICITNONE之前,模块的先后次序无关紧要。,.,26,3PUBLIC和PRIVATE属性信息隐蔽:PRIVATE,将模块内部使用的实体隐藏,实体访问只限于模块内;缺省访问属性:PUBLIC,外部程序只使用公共部分的实体。例如:REAL,PRIVATE:X将实型变量X规定为私有的,只能在模块内访问。PRIVATEX,Swop同时规定变量X,例程Swop为私有的。PRIVATEPUBLICSwop不带实体列表,除Swop外,其余的模块实体都是私有的。,.,27,第六节例程参数,形参(虚参):相对于实参而言例程在定义时,列表中的参数只是特定数据类型的占位符,系统不会为他们分配存储单元,称为形参或者虚参;例程被调用或引用时,列表中的参数被分配一定的存储单元,并接收外部实参传递进来的值;例程执行完毕,例程中的参数所占有的存储空间被系统自动释放,空间中保存的参数值也随之消失。例程中的局部变量具有同样的性质:例程执行时“生存”,例程不执行时“消亡”;如果声明变量具有SAVE属性,局部变量就是静态变量,从例程中被调用到程序结束,一直保存有特定的值。,.,28,1参数传递实参和虚参之间的数据传递(1)引用传递;(2)值传递。Fortran中参数(包括数组参数)通常是以引用方式传递,即地址传递;在实参为常量和表达式的情况下,参数是以值方式传递;若将变量实参括起来,该实参被转化为表达式,表达式以值方式传递。例如:CALLSub(A),B)其中,(A)是表达式,以值方式传递。*引用传递就是将实参的内存地址传递给虚参,例程中虚参的变化会反映到实参中;值传递就是将实参值的拷贝传递给虚参,虚参的变化不会影响实参。*为确保参数按用户的意愿进行传递,Fortran90提供了INTENT属性,例如:SUBROUTINESUB(X,Y,Z)REAL,INTENT(IN):X!向例程传入数据,拥有该属性的虚参不允许改变REAL,INTENT(OUT):Y!向例程传出数据,对应的实参必须是一变量REAL,INTENT(INOUT):Z!传出/传进数据,对应的实参必须是一个变量ENDSUBROUTINESUB,.,29,2参数类型匹配PROGRAMMainIMPLICITNONEEXTERNALSubINTEGER:X=1!对应实参X声明为整型CALLSub(X)PRINT*,X=,XENDPROGRAMSUBROUTINESub(A)IMPLICITNONEREAL,INTENT(INOUT):A!虚参A声明实型,对应实参为XA=A+1ENDSUBROUTINE例3-8中,参数类型不匹配,出错!,.,30,3可选参数参数列表可以很长,但并不是所有的参数都需要传递,这种情况下,可以规定部分或全部参数具有可选(OPTIONAL)属性。假如参数列表既有必选参数又有可选参数,那么所有的必选参数必须放在可选参数之前,先必选,后可选。例如一个外部例程Sub有6个参数,2个必选,4个是可选,调用程序中的接口块形式如下:INTERFACESUBROUTINESub(DumU,DumV,DumW,DumX,DumY,DumZ)REALDumU,DumV,DumW,DumX,DumY,DumZOPTIONALDumW,DumX,DumY,DumZENDSUBROUTINEENDINTERFACE,.,31,调用语句CALLSub(A,B)!1CALLSub(A,B,C,D)!2CALLSub(A,B,DumX=D,DumY=E,DumZ=F)!3对!1,只有必选参数DumU,DumV被传递;对!2,2个必选参数DumU,DumV和前面的2个可选参数DumW,DumX被传递;对!3,2个必选参数DumU,DumV和后边的3个可选参数DumX,DumY,DumZ被传递。对!1,!2,没有特别说明,参数传递按照列表顺序;对!3,可选参数可以不按声明的列表次序进行调用;若不按列表次序调用,可选的虚参名必须被引用(需要提供关键字参数列表)。一旦某个可选参数使用了关键字,其后面的可选参数都使用关键字。例如:CALLSub(A,B,DumX=D,E,F)是错误的外部例程使用可选参数,需要在调用程序中建立其接口块。,.,32,例3-9可选参数的使用MODULEModIMPLICITNONECONTAINSREALFUNCTIONFunc(X,A,B,C)!计算FUNC(X)=A*X2+B*X+C!A,B,C不传入,值为0REAL,INTENT(IN):X!X值一定要传入REAL,OPTIONAL,INTENT(IN):A,B,C!A,B,C可以不传入REALRA,RB,RCRA=0.0;RB=0.0;RC=0.0!几个简单的赋值语句放在一行IF(PRESENT(A)RA=A!检查可选参数是否存在IF(PRESENT(B)RB=BIF(PRESENT(C)RC=CFunc=RA*X*2+RB*X+RCENDFUNCTIONENDMODULEPROGRAMMainUSEModIMPLICITNONEPRINT*,Func(2.0,C=1.0)!F(2)=0*22+0*2+1=1PRINT*,Func(2.0,B=1.0,A=2.0)!F(2)=2*22+1*2+0=10ENDPROGRAM,.,33,例程重载:指不同参数列表的例程被赋予相同的名字,例程调用时,编译器会依据所传递的实参类型,按实参和虚参类型匹配的原则,调用或引用相关的例程。例如子程序Swop(X,Y),其功能是交换2个数的值。其中的2个参数,可以是实数,也可以是整数。例3-10MODULEModIMPLICITNONEINTERFACESwop!Swop是调用时使用的例程名MODULEPROCEDURESwopReal,SwopIntegersENDINTERFACE,第七节例程重载,.,34,!实型数据交换CONTAINSSUBROUTINESwopReals(X,Y)REAL,INTENT(INOUT):X,YREALTempTemp=XX=YY=TempENDSUBROUTINE!整型数据交换SUBROUTINESwopIntegers(X,Y)INTEGER,INTENT(INOUT):X,YINTEGER,TempTemp=XX=YY=TempENDSUBROUTINEENDMODULE!主程序PROGRAMMainUSEModIMPLICITNONEREAL:A=1.0,B=2.0INTEGER:I=1,J=2CALLSwop(A,B)CALLSwop(I,J)PRINT*,A=,A,B=,BPRINT*,I=,I,J=,JENDPROGRAM,.,35,建立重载例程接口块,以调用的例程名命名接口块:INTERFACESwopMODULEPROCEDURESwopReals,SwopIntegersENDINTERFACE体的例程作为外部例程,调用程序过程中建立的接口块为:INTERFACESwop!相比一般的例程接口块,多了接口名SwopSUBROUTINESwopReals(X,Y)REAL,INTENT(INOUT):X,YENDSUBROUTINESUBROUTINESwopIntegers(X,Y)INTEGER,INTENT(INOUT):X,YENDSUBROUTINEENDINTERFACE,.,36,递归例程:在一个例程体内出现直接或间接调用例程自身的语句,称该例程为递归例程。递归例程的典型例子是计算n!Fortran90支持递归,但必须添加RECURSIVE关键字,在例程是函数的情况下,还须添加RESULT子句;在递归函数体内引用函数自身时,用的是函数名(Factorial),赋值给函数时,用的是结果名(Fact)。,第八节递归例程,.,37,例3-11递归函数求n!PROGRAMMainIMPLICITNONEINTEGERIDOI=1,10PRINT*,I,!=,Factorial(I)ENDDOCONTAINSRECURSIVEFUNCTIONFactorial(N)RESULT(Fact)INTEGERFact,NIF(N=1)THENFact=1ELSEFact=N*Factorial(N-1)!引用的是函数名Factorial!赋值采用的是FactENDIFENDFUCTIONENDPROGRAM,.,38,递归算法简单直观,容易编写程序,但递归算法执行效率低,原因是递归包含递推和回归2个过程,系统分别要进行进栈和出栈操作。例如求5!,递推过程:5!=54!4!=43!3!=32!2!=21!1!=1回归过程:2!=21!=23!=32!=64!=43!=245!=54!=120所以递归程序设计除了要找出递归表达式外,还要确定递归的终止条件(如:1!=1),无限递归没有任何意义;在递归子程序下,同样须添加RECURSIVE关键字。,.,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论