第八章子程序

上传人:博****1 文档编号:569707881 上传时间:2024-07-30 格式:PPT 页数:121 大小:238.51KB
返回 下载 相关 举报
第八章子程序_第1页
第1页 / 共121页
第八章子程序_第2页
第2页 / 共121页
第八章子程序_第3页
第3页 / 共121页
第八章子程序_第4页
第4页 / 共121页
第八章子程序_第5页
第5页 / 共121页
点击查看更多>>
资源描述

《第八章子程序》由会员分享,可在线阅读,更多相关《第八章子程序(121页珍藏版)》请在金锄头文库上搜索。

1、第八章第八章子程序子程序8.1语句函数语句函数8.2函数子程序函数子程序8.3子例行程序子例行程序8.4程序单元之间的数据传递程序单元之间的数据传递8.5递归调用递归调用8.6数据共用存储单元与数据块子程序数据共用存储单元与数据块子程序8.7内部子程序内部子程序8.8模块模块8.9程序举例程序举例子程序是构造大型程序的有效工具,一个实用程序(不管是系统程序还是应用程序),一般都含有多个子程序。FORTRAN90中的子程序按子程序完成的功能划分有子例行程序、函数子程序、数据块子程序等,按是否定义在某个特定的程序单元内部来划分有程序单元子程序、模块子程序以及内部(INTERNAL)子程序等,这些通

2、称为子程序,子程序不能独立运行,它们和一种称为主程序(就是本章前读者已经熟知的程序结构)的程序单元一起组成一个实用程序。一个程序可以不含子程序,但不能缺少主程序。本章讨论各种子程序的结构、功能以及子程序与主程序或子程序之间的数据交互作用。语句函数不具备子程序的一般书写特征,但其作用与子程序相同,也一并放在本章讨论。通过本章的学习,读者应能熟练地选择并设计恰当的子程序形式来构造自己的程序,从而提高程序设计能力。8.1语句函数语句函数在第二章中,读者使用过了诸如SIN(X)、SQRT(X)这些内在(INTRINSIC)函数。也有教科书称这一类函数为内部(INTERNAL)函数,但为了区别另外一种内

3、部子程序结构,本章称由FORTRAN编译器提供的函数为内在函数。这些内在函数是在程序设计过程中使用频率很高,并且一般实现比较复杂的函数。用户在使用内在函数时,并不需要对函数的实现过程进行描述,只需按照FORTRAN90手册要求使用即可,FORTRAN90编译器“认识”这些内在函数并能正确完成函数所规定的功能。但是,在实际设计过程中,用户还会遇到大量的并未包含在内在函数中的其他函数,计算这些函数时,就不能象内在函数那样仅仅使用函数名来使用这些函数,而必须在适当的地方以FORTRAN90能“理解”的形式向FORTRAN90编译器说明这些非内在的函数的计算过程与参数类型,当函数的计算过程简单到可以用

4、一个语句定义清楚时,这样的定义语句就称为语句函数。例8.1设多项式函数设计一个程序,计算f(1)、f(10)、f(12)、f(-5)的值。程序如PROGRAMEXAM1A:PROGRAMEXAM1AX=1FX=5*X*3-2*X*2+7*X+6WRITE(*,*)f(,X,)=,FXX=10FX=5*X*3-2*X*2+7*X+6WRITE(*,*)f(,X,)=,FXX=12FX=5*X*3-2*X*2+7*X+6WRITE(*,*)f(,X,)=,FXX=-1FX=5*X*3-2*X*2+7*X+6WRITE(*,*)f(,X,)=,FXEND显然,程序EXAM1A不简练,把一个相同的函数

5、表达式重复了多遍,如果能定义一个函数f(x),然后分别使用1、10等参数来调用f(x),将会有效的简化程序量,这就是本节要讨论的内容。811语句函数的定义语句函数的定义如前所述,由于FORTRAN90的编译器不“认识”一般的函数f(x),不知道怎样计算f(x)的函数值,因而,在使用(称为函数调用)函数时,必须向FORTRAN90编译器说明该函数的计算方法,这种说明过程称为函数定义。语句函数定义的一般格式是:1.语句函数名在语句函数定义格式中,f称为函数名,函数名的组成规则与变量名相同。如果没有在语句函数定义语句前用类型语句说明该函数名的数据类型,则该语句函数的函数值的类型按其函数名遵守IN隐含

6、规则。如f函数隐含为实型函数,而nf则隐含为整形函数。F(X,Y)=X*2+Y*2!定义了一个实型函数FINTEGERF(X,Y)=X*2+Y*2!定义了一个整型函数FNF(X,Y)=X*2+Y*2!也同样定义了一个整型函数F语句函数不能与同一个程序单元中的变量同名。2.语句函数的虚参在语句函数定义语句中的函数参数称为虚参,他们本身是没有值的,只有在函数调用时才用实际参数(称为实参)代替。实参或是常数、或是一个有确定值的变量、或是一个可以计算值的表达式。虚参在形式上与普通变量相同,一个语句函数中的虚参不能同名。不同语句函数中的虚参可以同名,虚参也可以和程序中的变量同名。当没有语句对虚参的数据类

7、型进行说明时,虚参的类型遵守IN隐含规则;当使用了类型说明语句对虚参类型进行说明后,这种说明对于虚参以及与虚参同名的变量同时有效。INTEGERZF(X)=3*X*2+5G(Y)=3*Y*2+5H(Z)=3*Z*2+5在上述程序中,函数F和G本质上是一个函数,因为对于任意的实参T,F(T)和G(T)总是相同的,但函数F、G和H有点不同,其虚参Z被说明为整型。当虚参个数多于一个时,虚参间用逗号分隔,当没有虚参时(这样的语句函数没有使用价值),函数名后的括弧也不能省略。3.语句函数表达式语句函数表达式说明函数与参数的对应关系,在函数表达式中,可以包含常量、变量、函数虚参(虚参必须包含在表达式中)、

8、FORTRAN90内在函数、数组以及前面已经说明了的语句函数。4.关于语句函数的进一步说明(1)只有当函数关系简单,可以用一个语句描述函数与参数的对应关系时,才能使用语句函数。(2)语句函数是非执行语句,语句函数的定义语句要放在一个程序单位的所有其他说明语句之,并放在所有可执行语句之前。(3)语句函数只有在本程序单元中才有意义。也就是说,不能使用其他程序单元中的语句函数。(4)语句函数中的虚参必须是变量,不能是常量、数组元素和内在函数等。(5)语句函数是有类型的,因而语句函数表达式的类型一定要和其函数名的类型相容812语句函数的调用语句函数的调用语句函数一经定义,就可以在同一个程序单元中调用它

9、,调用的形式和内在函数完全相同。函数调用要注意以下两个问题:1调用时可以使用常量、变量、内在函数以及它们的表达式作为实参代替对应的虚参位置,但要保证实参与虚参具有完全相同的类型,并且实参是可以计算值的(即调用前实参中包含的变量全部已经赋值。)2实参和虚参个数相同。例8.2用函数语句的方法设计例8.1PROGRAMEXAM1BINTEGERXF(X)=5*X*3-2*X*2+7*X+6WRITE(*,*)F(2),F(10),F(12),F(-2)END8.2函数子程序函数子程序语句函数由于要求在一个语句中完成函数的定义,因而它只能解决一些较简单的问题,当函数关系比较复杂,用一个语句无法定义时,

10、语句函数就无能为力了,这时需要用到函数子程序。821函数子程序的定义函数子程序的定义函数子程序是以保留字FUNCTION开头,并以保留字END结束的一个程序段,该程序段可以独立存储为一个文件,也可以和调用它的程序单元合并存储为一个程序文件。函数子程序的定义格式是:类型说明FUNCTION函数名(虚参表)函数体END函数名的命名方法与变量名相同,虚参可以是简单变量和数组变量,但不能是常数、数组元素、表达式)例8.3编程,求:分析:上述三个数列的通项不同,求和范围也不同,用一个程序段难以同时计算三个数列的和,并且,因为无法用一个语句函数完成数列的求和计算,所以也无法使用语句函数来简化程序设计。下面

11、用函数子程序来完成这个问题。程序如下:FUNCTIONSM(M,N,L)SM=0DOI=M,NIF(L0)THENSM=SM+I*LELSESM=SM+(1.0*I)*L!进行实型运算ENDIFENDDOENDFUNCTIONSMPROGRAMEXAM2!开始主程序单元定义WRITE(*,*)S1=,SM(1,100,2)!调用函数子程序SM完成S1的计算WRITE(*,*)S2=,SM(100,140,3)WRITE(*,*)S3=,SM(20,50,-1)END程序运行结果如下: S1= 338350.000000 S2= 7.291440E+07 S3= 9.514656E-01对程序E

12、XAM2作如下说明:程序的第一部分是函数子程序的定义部分,如前所述,它可以单独存储为一个程序文件。从保留字PROGRAM开始至END是主程序部分,一个程序总是从主程序开始运行的,主程序的第24个语句都要打印函数SM的值,这时调用函数定义部分,根据函数的定义描述计算函数的值并予以打印。三个打印语句分别调用了三次函数子程序(即执行了三次函数子程序),从这里我们可以看到:采用函数子程序设计程序时并没有提高程序的执行效率,但却可以有效的提高程序的设计效率。当函数子程序的定义过程和主程序放到一个程序文件中时,存储顺序是任意的,函数子程序可以放到主程序之前(如EXAM2),也可以放到主程序之后,读者应该清

13、楚,程序总是从主程序开始执行。函数定义部分应注意如下问题:1函数值的类型可以在函数定义时予以说明,下面的两种说明方法是等效的:(1)INTEGERFUNCTIONF1(X1,X2.XN)函数体END(2)FUNCTIONF1(X1,X2.XN)INTEGERF1函数体END都说明F1是一个整型函数,当未使用这种显示的类型说明时(如例8.3),函数值的类型遵守IN隐含规则。2函数不能有同名虚参。虚参的类型可以在函数体中进行说明方法,当未对虚参类型进行说明时,虚参类型遵守IN隐含规则。3函数定义部分中一定要有一个语句将函数值赋值给函数名(如例8.3中的第5句和第7句)。这种赋值语句的格式是:函数名

14、=表达式注意不要在函数名后带上括弧,写成:函数名(虚参表)=表达式822函数子程序的调用函数子程序的调用定义函数子程序的目的是为了调用。不仅主程序可以调用一个函数子程序,函数子程序也可以调用其它的函数子程序,甚至于还可以调用本身(递归调用)。调用程序称为主调程序单元,而被调用的函数子程序称为被调程序单元。调用一个函数子程序的方法和调用内在函数和语句函数的方法基本相同:1调用时应该用实参代替函数子程序定义部分的虚参,实参和虚参的类型要相同。和语句函数一样,实参可以是常量、变量、表达式等。2调用程序单位中的变量不能与函数子程序同名。函数值的类型由函数定义程序单元决定,与调用程序单元无关。3当函数名

15、的类型不满足IN隐含规则时,在调用程序单元中要对函数名的类型给出说明(如例8.4中的主程序EXAM3的第2句。)4不能调用一个没有定义的函数子程序(这一点和内在函数是不同的。)例8.4用函数子程序的方法设计一个程序,求50100内的所有素数及其和。分析:设计一个函数子程序PRIME(N),函数PRIME的值定义如下:主程序的任务是应用PRIME函数子程序在50100之间使用枚举法求出那些使PRIME函数值为1的自然数并求这些数的和。函数子程序如下:FUNCTIONPRIME(N)INTEGERPRIME*定义PRIME是整型函数PRIME=0DOI=2,N-1IF(MOD(N,I)=0)GOT

16、O10*参数N有因子I,非素数,退出循环ENDDOPRIME=1*参数N无任何因子,函数值为110END主程序如下:PROGRAMEXAM3INTEGERPRIME*说明要调用的函数PRIME为整型DOI=50,100IF(PRIME(I)=1)THENS=S+IWRITE(*,*)IENDIFENDDOWRITE(*,*)S=,SEND运行结果如下: . 83 89 97 S= 732.000000例 8.5 当一个数各个数位的立方和等于这个数本身时,称这样的数为水仙花数(如153=1*3+5*3+3*3,所以,153是一个水仙花数,)编程:求100999之间的水仙花数。分析:设计一个函数子

17、程序NUM(N,I),当I=100时,函数NUM返回N的百位上的数;当I=10时,NUM返回N的十位上的数,I=1时,NUM返回N的个位上的数。主程序中调用NUM函数在100999之间找出所有水仙花数。程序如下:PROGRAMFLOWERDOI=100,999IF(NUM(I,100)*3+NUM(I,10)*3+NUM(I,1)*3=I)THENWRITE(*,*)IENDIFENDDOENDFUNCTIONNUM(N,I)SELECTCASE(I)CASE(100)NUM=N/100!用N百位上的数赋值给函数名CASE(10)NUM=MOD(N/10,10)!用N十位上的数赋值给函数名CA

18、SE(1)NUM=MOD(N,10)!用N个位上的数赋值给函数名ENDSELECTEND程序运行结果如下: 153 370 371 407除了函数子程序外,还有一种子例行子程序,函数子程序和子例行子程序都是一种独立的程序单元,二者的差别是:函数子程序的名字代表一个值,因而是有类型的,而子例行程序的名字不代表一个值,因而其名字没有类型问题。从使用上来说,二者是可以相互替代的。831子例行子程序的定义子例行子程序的定义子例行子程序是由保留字SUBROUTINE开头,到保留字END结束的一个程序段。其定义格式是:SUBROUTINE子程序名(虚参表)子例行程序体END子程序的命名方法与变量相同。虚参

19、由变量、数组名(不能是数组元素,常数、表达式)充当,当虚参多于一个时,各虚参间用逗号分隔,当没有虚参时,子例行程序名后的一对括弧可以省略。子例行程序的设计方法和函数子程序相同,但因为其名字没有值,所以不能有对子例行程序的名字赋值的语句。83子例行程序子例行程序832子例行子程序的调用子例行子程序的调用子例行程序的调用格式是:CALL子例行程序名(实参表)其实参的类型与函数子程序相同。和函数子程序的调用不同的是,子例行子程序的调用是一个独立的语句。子例行程序调用的其它事项与函数子程序的调用相同。下面通过两个实例来讨论函数子程序与子例行程序的相同点与不同点。例8.6用子例行程序的方法完成例8.3分

20、析:例8.3中定义了一个函数SM(M,N,L),我们将该函数子程序修改为一个子例行程序SM(S,M,N,L),虚参M,N,L的含义与例8.3相同,虚参S用来存储结果和(用来替代函数名SM)。程序如下:SUBROUTINESM(S,M,N,L)DOI=M,NIF(L0)THENS=S+I*LELSES=S+(1.0*I)*LENDIFENDDOENDPROGRAMEXAM5CALLSM(S1,1,100,2)CALLSM(S2,100,140,3)CALLSM(S3,20,50,-1)WRITE(*,*)S1=,S1WRITE(*,*)S2=,S2WRITE(*,*)S3=,S3END运行结果如

21、下: S1= 338350.000000 S2= 7.291440E+07 S3= 9.514656E-01例8.7用随机方法生成一个包含20个元素的数组,对该数组按升序排序打印。数据排序的问题读者在第七章已经很熟悉了,下面直接给出程序:PROGRAMEXAM5PARAMETER(N=20)DIMENSIONA(N)INTEGERAA(1)=17该语句及随后的三个语句生成数组ADOI=2,20A(I)=MOD(19*A(I-1),1024)ENDDODOI=1,N-1二重循环完成对A的排序DOJ=I+1,NCALLSWAP(A(I),A(J)ENDDOENDDOWRITE(100,200)(A

22、(I),I=1,N)200FORMAT(2(2X,10(I5,X)/)END子例行程序SWAP(M,N)的功能是,若MN,就交换M、N的值,程序段如下:SUBROUTINESWAP(X,Y)INTEGERX,Y,TIF(XY)THENT=XX=YY=TENDIFEND程序执行结果是: 3 17 57 59 115 137 139 169 305 321 323 537 545 555 593 675 891 979 987 1017从上面两个例题可以看出:1子例行程序和调用它的主程序的存放顺序是无关紧要的,既可以将子程序存放在前,也可以将主程序存放在前,还可以作两个程序文件分别存放。2子例行程

23、序和函数子程序在使用上可以相互替代。但是,当要求一段子程序有返回值时,以选择函数子程序比较方便(如例8.6),当子程序没有返回值时(如例8.7),则选择子例行程序较为方便例8.8设计一个自例行程序程序,求任意矩阵的转置矩阵。设计一个子例行程序TRAN(A,B,M,N)完成将矩阵A转置后放矩阵B,M、N分别是矩阵A、B的行数和列数。主程序如下:PROGRAMEXAM6PARAMETER(M=3)PARAMETER(N=4)DIMENSIONA(M,N),B(N,M)INTEGERA,BWRITE(*,*)pleaseinputa3x4MatraREAD(*,200)(A(I,J),J=1,N),

24、I=1,M)CALLTRAN(A,B,M,N)WRITE(*,300)(B(I,J),J=1,M),I=1,N)200FORMAT(4I4)300FORMAT(3I5)END子例行程序如下SUBROUTINETRAN(A,B,M,N)INTEGERA(M,N),B(N,M),M,NDOI=1,MDOJ=1,NB(J,I)=A(I,J)ENDDOENDDOEND运行情况:pleaseinputa3x4Matra 1 2 3 4 5 6 7 8 9 10 11 12显示结果如下: 1 5 9 2 6 10 3 7 11 4 8 12841简单变量作为虚参简单变量作为虚参这是一种最常见的情况,例8.

25、4,8.5都是这种情况,在这种情况下,根据子程序调用时实参的不同类型,又可以进一步分为两种情况:1简单变量或数组元素作为实参FUNCTIONSUB(A,B)PROGRAMTTEMX=3.Y=-5S=S+SUB(X,Y).ENDEND不同程序单元之间的数据传送方法有参数的虚实结合、建立公用区及通过数据文件等三种方式实现。本节先讨论参数的虚实结合方法,8.7节讨论公用区的概念与用法,第十一章讨论文件方法。图8.1A、X,B、Y共用存储单元8.4程序单元之间的数据传递程序单元之间的数据传递此种情况下FORTRAN90系统将实参与虚参安排同一个存储单元,对虚参的任何改变都作用在对应的实参上,因而调用一

26、个子程序(包括函数子程序和子例行程序)时,实参的值有可能改变。如图8.1所示:2常量或表达式作为实参当用常量或表达式作为实参时,FORTRAN90编译器首先计算表达式的值(如果实参为表达式时。)然后将该值赋值给对应的虚参。此种情况下,子程序中不能改变与常量(或表达式)对应的虚参的值,否则结果难以预料。842数组名作为虚参数组名作为虚参当虚参是数组名时,对应的实参可以是与虚参类型相同的数组名或数组元素,并且实参与虚参共用一片连续的存储单元。1虚参为数值型或逻辑型数据(此时的实参当然也是对应类型)(1)实参为数组名时,FORTRAN90编译器将实参数组的第一个元素的存储地址传送给子程序,并将其作为

27、对应虚参数组的第一个元素的存储地址,从而使两者共用一片存储单元。(2)当实参是一个数组元素时,FORTRAN90编译器将该元素的存储地址传送给子程序,并将其作为对应虚参数组的第一个元素的存储地址,从而使虚参数组与实参自该元素以后的元素共用一片存储单元。在实参与虚参数组之间传送数据时,不要求两者的行列数相同,甚至于实参元素的个数可以多于虚参(这种情况下,多余的实参不参与子程序中的运算。)读者应该牢记:FORTRAN90是按列为主存放多维数组的,实参和虚参间的元素按存储顺序对应。如:PROGRAMTTSTFUNCTIONSUB2(X)DIMENSIONA(3,4)DIMENSIONX(2,6)DO

28、I=1,3S=0DOJ=1,4DOI=1,2A(I,J)=I+JDOJ=1,6ENDDOIF(MOD(I+J,3)=0)THENENDDOS=S+X(I,J)WRITE(*,*)SUB2(A)ENDIFENDENDDO在程序TTST的倒数第二句调用了函数子程序SUB2,虚参X是一个2x6的矩阵,而实参A是一个3x4的矩阵,两者的元素对应关系是:A(1,1)X(1,1),A(2,1)X(2,1),A(3,1)X(1,2)A(1,2)X(2,2),A(2,2)X(1,3),A(3,2)X(2,3)A(1,3)X(1,4),A(2,3)X(2,4),A(3,3)X(1,5)A(1,4)X(2,5),

29、A(2,4)X(1,6),A(3,4)X(2,6)在函数子程序SUB2中,满足求和条件的元素分别是:X(2,1),X(1,2),X(2,4),X(1,5)这些元素对应的实参元素是:A(2,1),A(3,1),A(2,3),A(3,3)故所求的函数值为:3+4+5+6=182虚参为字符型数据当虚参为字符型数据时(当然对应的实参也为字符型数据),实参和虚参不是按照数组元素的顺序对应,而是按照字符位置一一对应,读者只要了解FORTRAN90中字符型数据的存储规则,并将实参与虚参的存储顺序派出来,就不难确定实参元素与虚参元素的对应关系,这里不再详细说明。3可调数组请读者重新考察例8.8中的子例行程序T

30、RAN(A,B,M,N),在子程序的说明中将A、B说明为A、B分别是一个M*N的矩阵,注意在子程序中并没有具体规定M、N的值,这样的数组称为可调数组,可调数组的引入提高了子程序的适应性,大大提高了编程效率。应注意可调数组只能作为虚参使用,不能在主程序中使用可调数组,也不能在子程序的其它地方使用可调数组。843子程序名作为虚参子程序名作为虚参子程序的虚参不仅可以是前面所述的各种数据类型,还可以是一个子程序名。例8.9设有三个连续函数:分析:用Simpson方法求函数的积分时要计算被积函数的函数值,因为三个被积函数不同,求其函数值的方法也就不同,要设计一个统一的函数子程序,必须设计一个虚参函数,并

31、用被积函数作为实参来调用该函数子程序。用Simpson方法求函数定积分的函数子程序如下:首先定义三个被积函数F(X)、G(X)、H(X)的函数子程序:FUNCTIONF(X)!被积函数F(X)F=SIN(3*X)+COS(X)ENDFUNCTIONG(X)!被积函数G(X)G=5*X*3+2*X-10ENDFUNCTIONH(X)!被积函数H(X)H=1/(1+X*2)END再建立SIMPSON求积分函数子程序FUNCTIONSIMPSON(F,A,B)H=(B-A)/2C=(A+B)/2SIMPSON=H*(F(A)+4*F(C)+F(B)/3ENDPROGRAMSIMPSON_PROEXT

32、ERNALF,G,H!三个被积函数都非FORTRAN90内在函数REALI1,I2,I3!故定义三个函数名F、G、H为!计算F(X)的积分!外部函数(EXTERN属性)I1=SIMPSON(F,0,2*3.1416)I2=SIMPSON(G,0,10.0)I3=SIMPSON(H,0,1.0)WRITE(*,*)I1=,I1WRITE(*,*)I2=,I2WRITE(*,*)I3=,I3END程序的执行结果是: I1= -2.094445 I2= 12500.000000 I3= 7.833334E-01关于实参函数名的说明:1EXTERNAL和INTRINSIC调用虚参中有程序名的子程序(包

33、括函数子程序和子例行程序)时,我们要在虚参的位置代之以一个实际存在的子程序名作为实参,实参子程序如果是FORTRAN90的内在函数,则在调用程序段中要用保留字INTRINSIC对该程序名作出说明,如果实参子程序是自己设计(或调用他人的程序库)的,则必须用保留字EXTERNAL对实参程序名作出说明(如例8.9),这种对函数名属性的说明就和对变量的类型进行说明一样,说明语句必须放在该程序段的所有可执行语句前。必须强调:只需对实参的属性进行说明,至于虚参,因为其只是一个并不存在的形式子程序,并不具有INTRINSIC属性或EXTERNAL属性,是无法也无需说明其属性的。2内在函数的专用名和通用名FO

34、RTRAN90的内在函数有通用名和专用名之分(部分函数的通用名和专用名一致),用FORTRAN90的内在函数作为实参时,只能使用这些函数的专用名而不能使用其通用名。844星号星号(*)作为虚参作为虚参星号(*)也可以作为虚参,与星号(*)虚参对应的实参是一个冠有星号(*)的语句标号。如:PROGRAMTESTSUBROUTINEF(S,*,*).IF(条件1)THEN.RETURN1!return与1之间有空格REACLLF(A,*100,*200)ELSE*100.GOTO300RETURN2*200.ENDIF.300ENDEND例8.10设计一个子例行程序,当参数C为加号(+)时,计算并

35、打印A+B的值,C为减号(-)时,计算并打印A-B的值。SUBROUTINEF(A,B,C,*,*,S)CHARACTER*1C!定义参数C为单个字符变量SELECTCASE(C)CASE(+)S=A+BRETURN1!返回到第一个冠有*号的语句标号CASE(-)S=A-BRETURN2!返回到第二个冠有*号的语句标号ENDSELECTENDPROGRAMTESTCHARACTER*1CWRITE(*,*)PLEASEINPUT2NUMBERANDAOPERATIONSIGNREAD(*,*)A,B,CCALLF(A,B,C,*10,*20,S)10WRITE(*,*)A,+,B,=,S!C参

36、数为加号返回到此GOTO3020WRITE(*,*)A,-,B,=,S!C参数为减号返回到此30END应该指出,象上面这样的分支问题,可在子程序单元F或调用程序单元TEST中用分支程序很容易地实现,这里采用的子程序中根据分支条件而返回到不同的出口的方法,违背了一个程序单元应具有单一出口的结果化原则,是不应提倡的,读者在程序设计的实践中应尽量避免这种用法。845变量的作用域变量的作用域变量是为了完成一个计算任务而设置的一些数据存储单元。FORTRAN90为每一个变量在内存区域中建立一个物理的连续存储区,一旦某个变量完成其使命,FORTRAN90将释放该变量所占据的物理存储区,该变量变得无定义。程

37、序设计人员不能使用已经被FORTRAN90释放的变量。到底FORTRAN90何时为变量建立物理的存储区,又何时释放这些存储区呢?下面就来讨论这些问题。1变量存储区的分配与释放一个程序(是一个完整的程序而非组成程序的各程序单元)在投入运行时,系统为这个程序的全部变量一次性分配存储单元,当这个程序退出运行时,系统收回这个程序所占据的全部存储单元。一个程序中的全部变量被同时建立存储单元。一般来说,一个程序的变量单元也将被同时释放,除非我们声明保留某个变量的存储单元。2变量作用域一个变量通常只在本程序单元(这里是程序单元而非整个程序)中起作用,离开建立该变量的程序单元,变量就失去了定义,这种作用域的局

38、限性,使用户在设计程序时,只需考虑在本程序单元中的变量只否有相互干扰,而无需考虑与其它程序单元之间的变量干扰问题,简化了程序的调试工作。在程序调用时,调用程序单元的实参是通过与被调用程序单元的虚参的结合来实现的,并不是调用程序单元中的变量直接在被调用程序单元中有定义。为了帮助读者更清楚的了解这一点,下面举一个说明变量作用域的例子,请读者仔细分析程序、程序的说明以及程序结果,以弄清变量的作用域这一个重要问题。例8.11讨论变量的作用域SUBROUTINEF(A,B,C)INTEGERX,YX=5!子程序S中有X、YY=8C=A+BWRITE(*,*)X、YINSUB,X,YENDPROGRAME

39、XAM8U=5V=8X=3!主程序中也有X、YY=2CALLF(U,V,S)WRITE(*,*)X、YINMAIN,X,YWRITE(*,*)U,V,SEND程序的执行结果是: X、Y IN SUB 5 8 X、Y IN MAIN 3.000000 2.0000005.0000008.00000013.000000从程序执行结果可以看到,尽管在C程序单元EXAM8和程序单元VERY中都有变量X、Y,但其值是不相同的,说明它们是不相干的变量,只是同名而已。3子程序中变量的存储属性变量有数据类型,同时还有存储属性,数据类型决定变量的运算特征,而存储属性决定一个变量所占用的存储单元在什么时候被释放,

40、FPS中,变量的几种常见的存储属性有:(1)SAVE属性:当声明变量的子程序执行完毕后,具有SAVE属性的变量的存储状态依然保留,在下一次调用该子程序时,这些变量保持上一次调用返回时的值。(2)STATIC属性:具有该类属性的变量在整个程序(不是声明该变量的子程序)执行期中一直保留在存储单元中,这是变量的默认存储属性( 3) AUTOMATIC属 性 : 当 声 明 变 量 的 子 程 序 执 行 完 毕 后 , 具 有AUTOMATIC属性的变量的存储单元被系统回收。变量的存储属性的说明方法是:存储属性变量名表这里的存储属性是上述三种属性之一。如:AUTOMATICA,B,C!定义实型变量A

41、、B、C具有AUTOMATIC存储属性INTEGERSAVEX,Y!定义变量X、Y为整型,SAVE存储属性例8.12说明变量存储属性的作用。PROGRAMDATAS_TESTDOI=1,10WRITE(*,*)I,F()ENDDOENDFUNCTIONF()STATICN,S!定义N、S为STATIC属性N=N+1S=S+NF=SEND程序的执行结果是: 1 1.000000 2 3.000000 3 6.000000 4 10.000000 5 15.000000 6 21.000000 7 28.000000 8 36.000000 9 45.000000 10 55.000000如果将函

42、数子程序中的N、S变量定义为AUTOMATIC属性,结果与现在完全不同,请读者将修改后的程序上机调试运行,并分析程序结果。递归是一种很有用的数学思想,该种思想使得人们可以使用很简单的方法处理一些无穷概念。在程序设计语言中,所谓递归,就是允许在一个子程序的定义部分直接或间接地调用被定义子程序。FORTRAN语言在FORTRAN90以前的版本都不支持对子程序的递归定义,FORTRAN90增加了递归了这一功能,方便了用户。851递归的概念递归的概念数学上很多常见的概念能很好地说明递归的概念,为了帮助读者理解程序设计中的这一重要思想,下面讨论几个实例:第一个例子:自然数的定义。数学中自然数的定义是用递

43、归的方法给出的,其定义是:(1)1是自然数。(2)如果N是一个自然数,则N+1是一个自然数。在上述定义中,使用了“自然数”这一被定义的概念。第二个例子:阶乘函数的定义。上述定义中,使用(n-1)!来定义n!,其实还有很多这样的例子,如数学的一个分支图论中的图就是一个典型的递归定义的概念。85递归调用递归调用关于递归定义,读者应注意两个方面:第一、递归定义都应该有一个非递归的分支。如第一个例子中明确说明1是一个自然数(非递归定义),第二个例子中明确了1!=1,也不是采用递归的定义。非递归定义分支是正确推导的出发点。第二、在递归定义的递归分支中,被定义的概念和用来作为递归定义的概念在规模上有所不同

44、。如第一个例子中在假设n是一个自然数后,肯定n+1是一个自然数(规模越来月大,)第二个例子中用(n-1)!来定义n!(规模越来越小。)规模地改变是按照递归定义能在有穷步骤内解决问题的保证。如我们根据第一个例子中关于自然数的定义来判断某个数N是否自然数,根据定义,1是一个自然数,于是1+1=2是一个自然数,并且3、4.是自然数,如果N能由1加上有限个1得到,则N是自然数,否则不是。在第二个例子中,我们如果需要计算10!,根据定义的第二部分,得到10!=10*9!,对9!再继续使用定义,连续9次,得到:10!=10*9*8*7.*1852递归函数递归函数递归函数的定义格式是:RECURSIVEFU

45、NCTION函数名(虚参表)RESULT(变量名).调用该函数本身.END与一般函数子程序的定义格式比较,这里在保留字FUNCTION前加上了另一个保留字RECURSIVE,并且后面多了一个RESULT(变量)成分。该变量是FORTRAN90用来存放函数的中间结果变量,其类型应与函数名的类型相同。在递归函数的函数体中,给函数赋值不是赋值给函数名,而是给RESULT后面括号中的变量赋值。在退出函数子程序并返回到其调用程序单元之前,FORTRAN90会将该变量的值自动赋值给函数名。例8.13设计一个计算N!的函数子程序,并用其计算从键盘输入的任意自然数N的阶乘。函数子程序如下:RECURSIVEF

46、UNCTIONFAC(N)RESULT(FAC1)IF(N=1)THENFAC1=1!只能给FAC1赋值ELSEFAC1=N*FAC(N-1)!只能调用FAC函数ENDIFEND主程序如下:PROGRAMFAC_PROWRITE(*,*)PLEASEINPUTANUMBER.READ(*,*)NWRITE(*,*)N,!=,FAC(N)END运行情况是: PLEASE INPUT A NUMBER. 5 (并键入回车键) 5!= 120.000000在递归函数子程序中,不能直接给函数名赋值,而只能给RESULT变量(这里是FAC1)赋值,但在递归调用时,则必须使用函数名才可以,这一点请读者务必

47、注意。下面对该程序的执行过程作一些分析:程序从主程序FAC_PRO的第一个语句WRITE开始执行,屏幕上出现“PLEASEINPUTANUMBER.”提示。用户从键盘输入5,EXAM6用参数5调用函数子程序FAC,这是第一次调用,调用的程序单元是FAC_PRO。在函数子程序FAC中,因为实参5不等于1,执行函数体的ELSE块,以参数N-1=4调用FAC,这是第二次调用FAC,调用的程序单元是FAC本身,如此反复五次,到第五次调用FAC函数子程序时,调用参数N=1,执行FAC的IF块,计算出此时的函数值为1,并最终计算出函数值为120。如果在主程序FAC_PRO中,用户给N输入的值是一个负整数,

48、如-5,根据以上的分析,其递归调用过程是:FAC(-5)=-5*FAC(-6)=(-5)*(-6)*FAC(-7)=.因为调用实参永远不等于1,因而每一次的调用都引起一个新的递归调用,这样的递归过程显然没有完结的时候,为避免这种情况,应该在函数子程序FAC中有对N0)THENFAC1=N*FAC(N-1)!只能调用FAC函数ELSEFAC1=0!假定负数的阶乘函数值为0ENDIFEND程序中假定,当实参0时,函数值为0下面再讨论一个读者熟悉的例子。例8.14Fibonacci数列可以用下列函数形式来定义:设计一个函数子程序,计算Fib(n)。不用递归方法,读者也可以很容易的设计出求Fib(n)

49、的函数,但使用递归方法会使程序更自然一些,下面是使用递归方法的函数子程序:RECURSIVEFUNCTIONFIB(N)RESULT(FI)SELECTCASE(N)CASE(:-1)FI=-1!假定负数的函数值为-1CASE(0)FI=0CASE(1)FI=1CASE(2:)FI=FIB(N-2)+FIB(N-1)ENDSELECTEND程序FIB_PRO7用FIB函数子程序计算FIB(1)到FIB(10)的值。PROGRAMFIB_PROWRITE(*,*)(FIB(I),I=1,10)END结果是: 1.000000 1.000000 2.000000 3.000000 5.000000

50、 8.000000 13.000000 21.000000 34.000000 55.000000关于递归函数子程序,读者应注意:1函数子程序单元中不应该直接给函数名赋值,而应该给RESULT变量赋值,并且RELUST变量应和函数名的数据类型相同;2函数体一般由两个或两个以上的分支构成,其中至少有一个分支是非递归的(例8.10的IF块分支、例8.11的:-1,0,1三个分支都是非递归的),并且递归分支的参数应朝非递归分支的方向发展。853递归子例行程序递归子例行程序递归子例行程序的定义格式:RECRUSIVESUBROUTINE子例行程序名(虚参表).CALL子例行程序名(实参).END例8.

51、15设设计一个程序,求大于某个数据E的最小的S及对应的n分析:这个问题初看与递归问题无关,我们定义一个数列S(n)显然,这里用递归方式所定义的数列S(n)和前面非递归方式定义的数列S是相同的,解决这个问题的递归子程序如下:RECURSIVESUBROUTINESN(S,N,E)N=N+1S=S+1.0/NIF(SE)CALLSN(S,N,E)!未到规定值,递归END调用程序如下:PROGRAMEXAM_SNWRITE(*,*)PLEASEINPUTANUMBERTOEREAD(*,*)EN=0S=0CALLSN(S,N,E)WRITE(*,*)S=,S,N=,N,E=,EEND第一次调用结果:

52、 PLEASE INPUT A NUMBER TO E 3 (键入回车键) S= 3.019877 N= 11 E= 3.000000第二次调用结果: PLEASE INPUT A NUMBER TO E 5 (键入回车键) S= 5.002069 N= 83 E= 5.000000设计递归子例行程序应该注意:在递归子例行程序中,递归调用语句应处于一个分支块中,并且随着逐次的递归,分支条件会有不成立的时刻,否则,递归就没有结束的时刻。在例8.15中,递归调用语句置于分支条件(SA(J)THENT=A(I)A(I)=A(J)A(J)=TENDIFENDDOENDDOEND程序的运行结果是: 21

53、7. 366. 591. 972. 757. 666. 75. 344. 977. 902. 775. 164. 877. 50. 643. 432. 457. 158. 703. 124. 50. 164. 432. 666. 877. 75. 217. 457. 703. 902. 124. 344. 591. 757. 972. 158. 366. 643. 775. 977.前面的一组数是没有排序的,后面是排序后的结果,本例通过等价关系,把一个二维数组的问题简单的化为一个一维数组的问题,这也说明了等价语句的一种作用。两点说明:1FORTRAN90中容许定义不同类型的变量等价,但由于不同

54、类型的变量的数据存储形式不同,因而定义这种等价关系实际上是没有意义的。如:INTEGERAREALBEQUIVALENCE(A,B)此时整型数据A和实型数据B共享存储单元,但当A以整型数据格式存储在该存储单元中时,如果被B以实型数据格式读出后会变得面貌全非,反之亦然,读者不要认为二者的整数部分会相同,当读者学习过数据的物理存储方法后,就会了解产生这种不同的原因。2等价语句(EQUIVALENCE)只是建立同一个程序单元中几个变量之间的等价关系,不能实现不同程序单元之间的数据交换,不要试图通过定义不同程序单元之间的变量等价来实现程序单元间的通信。862公用数据块公用数据块一个应用程序是由一个主程

55、序单元和若干个辅助程序单元(函数子程序、子例行程序、数据块子程序、模块子程序等)组成,这些不同的程序单元为了完成一个共同的任务而相互支持、相互通信、协同工作,前面用了很大的篇幅讨论程序单元之间采用参数的虚实结合完成数据通信的方法,下面讨论数据传递的另外一种方法公用数据区。所谓公用数据区,就是一个程序中的每个程序单元都可以访问的公共区域。数据共用区分为有名公用区和无名公用区两种,一个程序只有一个无名公用区,但可以定义多个有名公用区。定义共用区的语句格式是:COMMON变量名表!在无名公用区中定义了一组变量COMMON/公用区名1/变量名表1,/共用区名2/变量名表2,.!在公用区1中定义了变量表

56、1,在公用区2中定义了变量表2。如:PROGRAMMAINFUNCTIONSUB()COMMONA,B,C,DCOMMONX,Y,Z,C.ENDEND上例中,主程序MAIN在无名公用区中定义了实型变量A、B、C,D而函数子程序SUB则在无名公用区中定义了实型变量X、Y、Z,C,因为MAIN程序单元与SUB程序单元同属于一个程序,其无名公用区是一个,因而,变量在内存中的存储形式如表8.1所示主程序(MAIN)变量名存储的数据子程序(SUB)中的变量名A3.5XB7.8YC-21.6ZD6.3C表8.1公用区变量存储示意图从表8.1可以看出,对同一个存储单元,MAIN程序单元以名字A调用,而SUB

57、程序单元以名字X调用,用这种方法建立起MAIN中A和SUB中X之间的联系,SUB中要传递数据给A的话只需向X赋予要传递的数据即可,反之亦然。公用区语句要注意的问题:1公用区中的变量按顺序对应,不是按名字对应,如上例中,MAIN中的变量C并不是与SUB中的C对应,而是与Z对应。2不同程序单元在COMMON语句中定义的变量个数不必相同,但只在前面相对应的变量间才建立了对应关系(公用存储单元)。3有对应关系的变量(公用存储单元)的数据类型应该一致,否则无实际意义。4不要把这里的公用存储单元关系和变量间的等价关系混淆:公用存储单元关系是不同程序单元之间的变量,而等价关系是一个程序单元内部的变量。5一个

58、程序单元中可以包含多个COMMON语句,如:COMMONX1,X2,X3,X4,X5,X6和语句序列COMMONX1,X2COMMONX3,X4,X5COMMONX6是完全相同的。6如果公用存储变量的名字不遵守IN隐含规则,则必须对这些变量进行数据类型的说明。如果某个程序单元在COMMON语句中存放了多个变量(比如说20个),而另一个程序单元只与其中的部分变量通信(比如说与第15个变量和第18个变量),因为公用区语句COMMON按顺序对应,因而在第二个程序单元的COMMON语句中必须也至少列出18个变量,不仅麻烦,还把不应与外部程序单元通信的16个变量与外部变量建立了公用存储单元关系,这些变量

59、的值受外部程序单元的影响,不符合模块化程序设计原则。为了克服这一问题,FORTRAN中引进了有名公用区的概念。比如对上述问题,可以使用有名公用区这样来解决。PROGRAMMAINCOMMON/ARY1/X1,X2,X3,X4,X5,X6,X7,X8,X9,X10COMMON/ARY2/X11,X12,X13,X14,X16,X17,X19,X20COMMON/ARY3/X15,X18.ENDSUBROUTINESUBCOMMON/ARY3/A,B.END这样就把MAIN中的X15、X18和SUB中的A、B变量建立了公用存储单元关系,并且没建立多余的公用存储关系。使用有名公用区除要注意和无名公用

60、区相同的问题外,还应注意:1公用区名字写在存储的变量名前,并用两个斜杠(/)括起来,公用区名字命名规则与FORTRAN的变量名相同,同一个程序(不是同一个程序单元)中的有名公用名不能相同。2不同程序单元之间按公用区名建立公用存储关系,也就是说:存储在不同名字的公用区中的变量没有关系,存储在相同名字的公用区中的变量按顺序建立公用存储关系。我们可以把无名公用区看作一种系统已定义好名字(因而无须在COMMON语句中说明公用区名)的特殊的有名公用区,这样就可以把两者统一起来。例8.17设计一个按分数规则进行加减法程序。分析:一般的分数加减法的形式是:分析:一般的分数加减法的形式是:其中:i=k*mn*

61、lJ=l*mi,j的最大公约数为1我们设计一个子程序完成i,j的计算,显然,子程序要从主程序中获取k、l、m、n等4个数据和一个运算符,并且要把结果i、j返回个主程序,这样,主子程序间共有7个量要进行通信。程序如下:SUBROUTINEADD!计算两个分数的和或差COMMONK,L,N,M,C,I,J!在无名公用区中定义7个通信变量INTEGER(1)C!定义C为单字节整型数INTEGERF1!定义函数子程序名F1为整型IF(C=1)THEN!C为运算符,1表示加法,-1表示减法N1=K*M+N*LELSEN1=K*M-N*LENDIFM1=L*MI=N1/F1(N1,M1)!F1(M,N),

62、函数子程序,求M、N的最大公约数J=M1/F1(N1,M1)!分子分母用最大公约数约分ENDSUBROUTINEADDINTEGERFUNCTIONF1(M,N)!求M、N的最大公约数INTEGERT,M1,N1,M,NM1=MN1=NIF(M1N1T=M1M1=N1N1=TENDIFT=MOD(M1,N1)DOWHILE(T0)!用辗转相除法求最大公约数M1=N1N1=TT=MOD(M1,N1)ENDDOF1=N1ENDFUNCTIONF1PROGRAMFRACTIONCOMMONN1,N2,N3,N4,C1,N5,N6!在无名公用区中存储7个变量与ADD通信INTEGER(1)C1INTE

63、GERN1,N2,N3,N4,N5,N6WRITE(*,*)PLEASEINPUTK,L,M,NREAD(*,*)N1,N2,N3,N4WRITE(*,*)PLEASEINPUTC(1,-1)READ(*,*)C1CALLADD()!调用ADD子程序求结果的分子分母IF(C1=1)THENWRITE(*,100)N1,N2,N3,N4,N5,N6ELSEWRITE(*,200)N1,N2,N3,N4,N5,N6ENDIF100FORMAT(I4,/,I4,+,I4,/,I4,=,I4,/,I4)200FORMAT(I4,/,I4,-,I4,/,I4,=,I4,/,I4)ENDPROGRAMFR

64、ACTION程序的运行结果是:第一次运行: PLEASE INPUT K,L,M,N1,2,1,3 (回车) PLEASE INPUT C(1,-1)1 (回车) 1/ 2+ 1/ 3= 5/ 6第二次运行: PLEASE INPUT K,L,M,N5,6,3,4 (回车) PLEASE INPUT C(1,-1)-1 (回车) 5/ 6- 3/ 4= 1/ 12863数据块子程序数据块子程序如果一个程序中要对一部分变量赋予相应初值,并且这些初值为该程序中几个不同的程序单元所引用,则可以建立一个特殊的程序单元,在该程序单元中对这些变量进行集中说明并使用DATA语句赋初值,完成这种任务的程序单元

65、称为数据块程序单元。数据块程序单元的形式是:BLOCKDATA程序名程序单元ENDBLOCKDATA如:BLOCKDATAEXAM_BLOCKDATAINTEGERA,B,C,DDIMENSIONA(100)COMMON/AREY1/ACOMMON/AREY2/B,C,DENDBLOCKDATAEXAM_BLOCKDATAFUNCTIONF(x,y)INTEGERX1,Y1COMMON/AREY2/X1,Y1/.ENDFPROGRAMTESTCOMMON/AREY2/M,N.ENDTEST上述示例中对主程序TEST的变量M、N和函数子程序F中的变量X1、Y1建立了公用存储关系并赋了初值0。数据

66、块子程序应注意如下问题:1数据块子程序中只能包含DATA、COMMON、EQUIVALENCE以及数据类型说明语句,不可包含任何可执行语句。2数据块中的公用区只能是有名公用区,并且对这些有名公用区中的所有变量,都必须使用COMMON语句一一排列。3数据块子程序不能被别的程序单元调用,它所要完成的功能(给变量赋初值)在该程序单元进行编译时即已完成。4数据块程序是一种特殊的程序单元,在数据块程序中进行的变量说明并不能代替其它程序单元中对变量的说明,并且,数据块子程序并没有在不同的程序单元之间建立变量的公用存储关系,不同程序单元之间变量的公用存储关系还是在各程序单元内部的数据说明部分完成的。8.7内

67、部子程序内部子程序前面所讨论的子程序,包括函数子程序、子例行程序和数据块子程序都是作为一个独立的程序单元,所谓独立的程序单元具有两个特征:1从形式上看:各种独立的程序单元的源程序是分别编写的,当上一个程序单元的代码编写完后(出现了程序单元的结束语句END),才开始另一个程序单元代码的编写,代码之间没有嵌套、没有交叉。2从变量的作用域来看,每个程序单元拥有一组独立的变量空间,各程序单元之间的变量是彼此独立的,相互不干扰。两个程序单元要传递数据时,要么使用参数的虚实结合方法,要么通过公用数据区。任何程序单元都不能直接引用其它程序单元的变量。如果一个子程序建立在某个程序单元的内部,那么这个子程序就不

68、再是一个程序单元,而是一个内部子程序。如:PROGRAMEX1PROGRAMEX2.CONTAINSEND!EX1结束SUBROUTINESUB2.SUBROUTINESUB1.ENDSUBROUTINESUB2END!SUB1结束END!EX2结束上例中,因为SUB1的程序代码是在主程序EX1结束后才开始书写,而SUB2的代码则嵌套在EX1的内部,所以子程序SUB1是一个与主程序单元EX1独立的程序单元,而子程序SUB2则只是主程序EX2中的一个内部子程序。不同的程序单元可以分别以不同的程序文件存储,也可以存储在同一个程序文件中,因此,读者不能以是否使用独立的程序文件存储来区分是否独立的程序

69、单元。程序单元与内部子程序的比较见表8.2。比较内容程序单元内部子程序源代码形式彼此独立,没有嵌套嵌套在另一个程序单元中变量作用域所有变量局部于本程序单元内部子程序可以引用该子程序所在的程序单元的全部变量,但子程序之外不能引用在内部子程序中建立的局部变量程序调用除PROGRAM程序单元外,子例行程序单元和函数程序单元可以为其它程序单元调用只能被内部子程序所在的程序单元调用表8.2程序单元与内部子程序的比较例8.18设计一个程序,求同时满足下列两个条件的分数X的个数:(1)1/6X子程序名功能:连接模块中的全部子程序和数据说明部分,使主调程序以指定别名调用模块中的某个子程序。格式三:USE模块名

70、,ONLY:子程序名功能:只连接模块中的指定程序,从而主调程序只能调用指定的子程序。如对于8.8.1节中的模块TEST_MOU而言,USETEST_MOU!本程序单元可以调用F、G、SWAP等三个子程序,但必须以模块中的名字来调用程序。USETEST_MOU,FUN=F!本程序单元可以调用F、G、SWAP等三个子程序,但必须用别名FUN调用模块中的F函数,函数子程序G和子例行子程序SWAP用模块中的名字。USETEST_MOU,ONLY:FUN=F!本程序单元只能以别名FUN调用模块中的函数子程序F,不能调用G和SWAP。关于模块调用的说明:1模块名和存储模块的文件名可以相同,也可以不同,US

71、E语句是以模块名而不是以模块文件名调用模块。2在FPS中,要调用本工程文件(ProjectFile)之外的模块时,应首先使用菜单中的Insert功能将要调用的模块文件插入到本工程文件中。例8.19设计一个程序,计算:因为模块TEST_MOU中有两个函数子程序F、G正好能计算S1、S2,我们调用该模块来实现本例程序。程序如下(模块程序清单不再列出)。PROGRAMTEST_MOU_PROUSETEST_MOU,funf=fWRITE(*,*)PLEASEINPUTANUMBER:READ(*,*)NWRITE(*,100)N,Funf(N)N1=NIF(MOD(N,2)=0)N1=N1-1WRI

72、TE(*,200)N1,G(N)100FORMAT(1+2+.+,I2,=,I5)200FORMAT(1+3*2+.+,I2,*2=,I5)END计算结果是: PLEASE INPUT A NUMBER:20 (输入回车) 1+2+.+20= 210 1+3*2+.+19*2= 1330 PLEASE INPUT A NUMBER:17 (输入回车) 1+2+.+17= 153 1+3*2+.+17*2= 9698.9程序举例程序举例这一节通过比较多的例题,帮助读者掌握子程序设计的思想、方法、技巧以及与子程序相关的一些语法要点。读者在学习本节时,应把重点放在程序设计的一般方法的学习上。例8.2

73、0用复合梯形公式求下列函数在-1,1上的积分。分析:将a,b等分为n个子区间,区间长度设为h,在每个子区间a+(i-1)h,a+ih上用的积分采用梯形方法求积分,则求函数f(x)在a,b上的复合梯型积分公式是梯型积分的子程序是:FUNCTIONTRAP(F,A,B,N)!梯形法求积分程序,F被积函数,A、B积分上下限,N区间分划数H=(B-A)/N!子区间宽度S=0DOI=1,NS=S+F(A+(I-1)*H)+F(A+I*H)!对每个子区间的积分采用梯形公式计算,并求和ENDDOTRAP=S*H/2END计算例题中的两个函数的积分主程序是:PROGRAMTRAP_PROPARAMETER(A

74、=-1,B=1)EXTERNALF,G!定义作为实参的函数子程序名F、G的属性WRITE(*,*)PLEASEINPUTANUMBERREAD(*,*)NWRITE(*,100)TRAP(F,A,B,N),TRAP(G,A,B,N)100FORMAT(2X,IF=,F6.2,IG=,F6.2)END此外,还有两个被积函数的函数子程序,分别是:FUNCTIONF(X)F=3*X*2+2*X-15ENDFUNCTIONG(X)G=1/(1+X*2)END计算结果是: PLEASE INPUT A NUMBER IF=-27.96 IG= 1.57上述4个程序段是4个程序单元,读者可能会认为无需将被

75、积函数F、G定义为函数子程序,而在主程序TRAP_PRO中以语句函数定义这两个函数会更简练,遗憾的是FORTRAN中,函数子程序实参的函数名必须是一个函数子程序而不能是一个函数语句,在TRAP_PRO中,F、G都作为了函数子程序TRAP的实参,因此,F、G只能是函数子程序。例8.21求方程F(X)=0的一个根,设分析:求方程的根一般采用迭代法,著名的牛顿迭代公式是:采用迭代法计算方程的根时,要给出一个迭代的初始值x0,将x0代入迭代公式的右端计算出x1,再将x1代入计算出x2.,当第n次和第(n+1)次的计算结果相等时,这个结果就是所求的方程的根,但一般不会出现两次结果完全相等的情况,在工程应

76、用中,当两次的结算结果差小于某一个控制参数E时,就把这个结果作为所求方程的近似根。根据上面的思想,设计出程序如下:PROGRAMNEWTONF(X)=7*X*4+6*X*3-5*X*2+4*X+3DF(X)=28*X*3+18*X*2-5*X+4!给出F(X)的导函数DF(X)WRITE(*,*)PLEASEINPUTX0ANDEREAD(*,*)X0,E!X0为迭代计算初始值,E为迭代控制值X1=X0X2=X1-F(X1)/DF(X1)DOWHILE(ABS(X1-X2)E)!当连续两次计算结果不小于给定参数E时循环迭代X1=X2X2=X1-F(X1)/DF(X1)ENDDOWRITE(*,

77、*)X1,F(X1)END程序运行结果是: PLEASE INPUT X0 AND E-1,0.001 (输入回车) -1.472319 1.579939E-02例8.22设计一个函数子程序GCD(M,N),求M、N的最大公约数。并用函数子程序GCD(M,N)求75,35,215三个数的最大公约数。设自然数M、N、k、r满足关系式:M=kN+r(k0,r=0)(1)其中k是M除以N的商,而r是余数,则由(1)不难看出:M、N的最大公约数等于N、r的最大公约数,因而我们可通过求N、r的余数达到求M、N的余数的目标。而N、r较原来的M、N小,容易计算其最大公约数,继续这一过程,当余数r=0时,这时

78、的除数就是所求的最大公约数。记M,N为M、N的最大公约数,上述计算递推过程是:M,N=N,r=N1,r1=.=Q,0其中,每一次求最大公约数的较大者是上一次的较小者,而本次的较小者是上一次的余数,当较小者为0时即得到了结果。根据这种思想设计的程序如下:INTEGERFUNCTIONGCD(M,N)INTEGERRM1=MN1=NIF(M1n1R=M1M1=N1N1=RENDIFR=MOD(M1,N1)DOWHILE(R0)!辗转相除M1=N1N1=RR=MOD(M1,N1)ENDDOGCD=N1END主程序如下:PROGRAMGCD_PROINTEGERGCD!调用函数名不遵守隐含规则的函数时

79、,必须对函数名作类型说明N=GCD(75,35)WRITE(*,*)75,35,215=,GCD(N,215)END这是一个很好的递归例题。本例未使用递归算法,请读者用递归算法重新设计子程序GCD(M,N),并自己总结递归与非递归算法的差异。例8.23设计一个函数子程序,求多项式:在任一点x0处的值。分析:为减少乘法计算量,对原多项式进行变形,得:并用其计算多项式:根据变形后的多项式公式设计的函数子程序如下:FUNCTIONPX(A,N,X0)DIMENSIONA(N+1)P=0DOI=1,NP=P*X0+A(I)ENDDOPX=P*X0+A(N+1)ENDFUNCTIONPX主程序如下:PR

80、OGRAMPX_PRODIMENSIONA(4)A(1)=5A(2)=2A(3)=-1A(4)=9WRITE(*,*)PX(A,3,5.0)END例8.24设计一个求两个矩阵乘积的子例行程序,并调用该程序求矩阵A、B的积,设:求矩阵乘积的方法想必读者已经熟悉,下面直接给出程序:SUBROUTINEMATRA_MUL(A,B,M,N,L,AB)!A(M,N)*B(N,L)=AB(M,L)DIMENSIONA(M,N),B(N,L),AB(M,L)DOI=1,MDOJ=1,LAB(I,J)=0DOK=1,NAB(I,J)=AB(I,J)+A(I,K)*B(K,J)ENDDOENDDOENDDOEN

81、D主程序如下:PARAMETER(M=3,N=4,L=3)DIMENSIONA(M,N),B(N,L),AB(M,L)DATAA/2.5,3.8,-45,1.5,4.5,23,12,5.9,34,2.4,24.5,0/DATAB/3.2,0,3.4,2.5,-7.8,-9.8,5.8,-56,5,4.5,7.8,210/CALLMATRA_MUL(A,B,M,N,L,AB)WRITE(*,100)(A(I,J),J=1,N),I=1,M)WRITE(*,*)WRITE(*,200)(B(I,J),J=1,L),I=1,N)WRITE(*,*)WRITE(*,300)(AB(I,J),J=1,L

82、),I=1,M)100FORMAT(2X,4F6.2)200FORMAT(2X,3F6.2)300FORMAT(2X,3F8.2)END计算结果如下: 2.50 1.50 12.00 2.40 3.80 4.50 5.90 24.50 -45.00 23.00 34.00 .00 3.20 -7.80 5.00 .00 -9.80 4.50 3.40 5.80 7.80 2.50-56.00210.00 54.80 -99.00 616.85 93.47-1411.52 5230.27 -28.40 322.80 143.70例8.25如果自然数n出现在n平方的右面(如5就出现在5的平方25的

83、右面),称满足这样条件的数为同构数,设计一个程序,求找出11000中所有的同构数。分析:我们用枚举法来解决上述问题,这样,问题的关键就是怎样判断一个任意数n是否出现在n的平方的右面。或者,更一般的说,对任意两个自然数m、n,怎样判断n是否出现在m的右面,判断的方法是对m用求余函数(MOD)截取与n相同的位数进行比较。例题解答中用一个子程序F来进行这一判断。程序如下:PROGRAMSAME_STRU!SAME_STRU中调用了内部函数子程序FDOI=1,1000IF(F(I*2,I)=1)WRITE(*,*)I,I*2ENDDOCONTAINS!内部子程序开始INTEGERFUNCTIONF(M

84、,N)!如果n出现在m的右面,f=1,否则f=0LEN_N=LOG10(REAL(N)+1!测定n的位数IF(MOD(M,10*LEN_N)=N)THEN!截取M右面与N等长的部分F=1ELSEF=0ENDIFENDFUNCTIONFENDPROGRAMSAME_STRU程序的运行结果如下: 1 1 5 25 6 36 25 625 76 5776 376 141376 625 390625例8.26MaCrathy91函数定义如下:设计一个计算M(n)的函数子程序Ma(n),并计算Ma(30),Ma(40),Ma(50), Ma(60), Ma(70), Ma(80), Ma(90), Ma

85、(100), Ma(110), Ma(120),Ma(150)的函数值。分析:Ma函数是用递归方法给出的,我们自然也应该首先考虑用递归函数调用来解决这一问题。本例比较简单,下面直接给出程序。RECURSIVEFUNCTIONMaCra(N)RESULT(Ma)IF(NA(J,1)THENT=A(I,1)A(I,1)=A(J,1)A(J,1)=TT=A(I,2)A(I,2)=A(J,2)A(J,2)=TENDIFENDDOENDDOENDSUBROUTINEPROGRAMEVEN_PROINTEGERA(54,2)DOI=1,54!A(i,1)随机数A(I,2)=IENDDOCALLEVEN(5

86、4,A)WRITE(*,100)(A(I,2),I=1,54)100FORMAT(5X,12I6)ENDPROGRAMEVEN_PRO程序运行结果是: 1 49 42 46 8 47 16 13 7 24 37 2 32 4 41 40 3 22 48 20 34 11 36 23 33 54 52 19 21 45 26 27 25 30 39 35 17 6 43 18 12 15 5 51 28 38 29 9 53 50 44 31 10 14例8.28设计一个程序。为参与玩扑克牌的4个人各分发12张牌,并给庄家多留6张牌。分析:分发扑克牌实质上是一个产生154的一个随机排列问题,而这

87、个问题已在例8.27中进行了详细的讨论。本例在显示界面上要进行一些处理,在FORTRAN90中,没有扑克牌中的诸如红桃、黑桃等符号,我们用字母数字代表每张扑克牌:A:黑桃A01A13分别代表黑桃1到黑桃KB:红桃B01B13分别代表红桃1到红桃KC:梅花C01C13分别代表梅花1到梅花KD:方块D01D13分别代表方块1到方块KE:国王A01A02分别大王和小王程序中使用字符数组B存储54张扑克牌。下面是程序及运行结果:SUBROUTINEEVEN(N,A,B)PARAMETER(K=219)INTEGERA(N,2),SEED,TCHARACTER*3B(N),T1DATASEED/29/S

88、AVESEEDA(1,1)=SEEDDOI=2,NA(I,1)=MOD(K*A(I-1,1),1024)ENDDODOI=1,N-1DOJ=I+1,NIF(A(I,1)A(J,1)THENT=A(I,1)A(I,1)=A(J,1)A(J,1)=TT=A(I,2)A(I,2)=A(J,2)A(J,2)=TT1=B(I)B(I)=B(J)B(J)=T1ENDIFENDDOENDDOENDSUBROUTINEPROGRAMEVEN_PROINTEGERA(54,2)CHARACTER*3B(54)DOI=1,54!产生54张按黑、红、梅、方顺序排列的扑克牌A(I,2)=IK1=I/13!K1代表扑克

89、牌的花色IF(MOD(I,13)=0)K1=K1-1K2=I-K1*13!K2是扑克牌的点数B(I)=CHAR(K1+65)/CHAR(48+K2/10)/CHAR(48+MOD(K2,10)ENDDOCALLEVEN(54,A,B)WRITE(*,200)(B(I),I=1,54)200FORMAT(12(3X,A)ENDPROGRAMEVEN_PRO程序的运行结果是: A01 D10 D03 D07 A08 D08 B03 A13 A07 B11 C11 A02 C06 A04 D02 D01 A03 B09 D09 B07 C08 A11 C10 B10 C07 E02 D13 B06

90、B08 D06 B13 C01 B12 C04 C13 C09 B04 A06 D04 B05 A12 B02 A05 D12 C02 C12 C03 A09 E01 D11 D05 C05 A10 B01上述结果中,每一行显示的是一方应该分发的12张扑克牌,而最后一行是多留给庄家的4张扑克牌。应该指出:例8.27和例8.28中的子例行程序所完成的主体功能相同,在实际编程时,读者应该将这样的子程序统一考虑,把基本的功能抽象出来组成一个子程序,把一些针对某些具体的问题的功能(如例8.28中把随机数列对应到扑克牌的功能)分配到主调程序单元(或另外写一个子程序),以提高子程序的通用性,减少程序设计量

91、。例8.29三个数之和是4426,钩掉较大数10位上的数就得到第二个数,钩掉较大数个位上的数就得到第三个数,求这三个数。分析:我们采用枚举法来解决上述问题。设L、M、N是满足条件的三个数,M是其中较大者,题目告诉我们L、M、N的和等于4426,则L应不小于4426/3并不超过4426-2等于4424。即L的取值范围是:1475L4424程序如下:PROGRAMGAME_NUMINTEGERF,GF(N)=10*(N/100)+MOD(N,10)!去掉N的10位部分G(N)=N/10!去掉N的个位部分DOL=1475,4424IF(L+F(L)+G(L)=4426)WRITE(*,100)L,F

92、(L),G(L)ENDDO100FORMAT(5X,3I10)ENDPROGRAMGAME_NUM程序的运行结果是: 3689 369 368例8.30用筛法求1000以内的所有素数。分析:筛法是一种古老的数学方法,基本思想是:在所有可能的结果中逐步地排除一切不可能的结果,最终余下的部分就是满足条件的解。用筛法求(1n)中的素数的方法是:(1)建立一个数组A,使A(i)=i,i=1,2.n(2)k=2(3)用A(k)试除A(i),i=k+1,k+2.n,将所有能被A(k)整除的数组元素赋值为0(此过程筛掉了1n中所有含A(k)的因子的数,故称此方法为师法)。(4)在A(k)之后找到第一个不为0

93、的数组元素,将其设为新的A(k),重复(3),直到k=n为止。(5)A中余下的不为0的数组元素就是问题的解。根据上述思想设计的程序及运行结果如下:SUBROUTINESIEVE(N,A,M)INTEGERA(N)DOI=2,N !A赋初值A(I)=IENDDODOI=2,N-1!筛法IF(A(I)0)THENDOJ=I+1,NIF(MOD(A(J),A(I)=0)A(J)=0ENDDOENDIFENDDOM=1DOI=2,N !将A中非元素(素数)排列到A的前面IF(A(I)0)THENM=M+1A(M)=A(I)ENDIFENDDOENDSUBROUTINESIEVEPROGRAMSIEVE

94、_PROPARAMETER(N=1000)INTEGERA(N)CALLSIEVE(N,A,M)WRITE(*,100)(A(I),I=2,M)100FORMAT(8I10)ENDPROGRAMSIEVE_PRO运行结果如下: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 . 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997例8.31设计一个子例行程序,去掉一个字符串中多余的空格。分析:什么是多余空格,题目中并未

95、明确说明,按计算机语言中一般的规定,单词之间一个空格和多个空格是等效的,下面按照这种要求设计的程序如下:SUBROUTINEWORD_SPACE(A)PARAMETER(N=80)CHARACTER*80A,B!B是一个工作变量K=0DOI=1,NIF(A(I:I)/=)THEN!非空格字符赋值K=K+1B(K:K)=A(I:I)ELSEIF(B(K:K)/=)THEN!只赋值一个空格(B(K:K)不为空格)K=K+1B(K:K)=A(I:I)ENDIFENDDOA=B!将工作变量B赋值给参数AENDSUBROUTINEWORD_SPACEPROGRAMWORD_SPACE_PROCHARAC

96、TERSTENCE*80open(10,file=f:word_space.txt)STENCE=IamastudentWRITE(*,100)STENCECALLWORD_SPACE(STENCE)WRITE(*,100)STENCE100FORMAT(X,A)END 运行结果如下: I am a student例 8.32,某农场有一头母牛。母牛每年初生一头小母牛,每头小母牛从第4年起又生一头小母牛,不计死亡情况,问第20年该农场共有多少头牛?分析:设计这一类程序的首要问题是找到解决该类问题的数学模型,初看起来,这个问题似乎很难,我们从最简单的情形着手分析,逐步找到规律,设A(n)表示第n

97、年农场拥有的母牛数量,显然有:A(1)=1A(2)=2 (母牛第2年生一头小牛)A(3)=3 (母牛第3年又生一头小牛)A(4)=3+2 (第3年的3头牛加上母牛和第1年生的小牛各生一头小牛一般说来,第n年拥有的牛数等于上一年度的牛数+本年度新生的小牛数,而本年新生的小牛数等于有生育能力的牛数,并非上一年度的牛都能生小牛,但前三年就存在的牛(其中最小的牛刚进入第4年)却都能生小牛,所以:A(n)=A(n-1)+A(n-3)这就是解决本例的公式,下面是根据这个公式设计的程序:RECURSIVE FUNCTION NUM_COW(N) RESULT(NUM_COW1)SELECT CASE(N)

98、CASE (1) NUM_COW1=1CASE (2) NUM_COW1=2 CASE (3) NUM_COW1=3 CASE (4:) NUM_COW1=NUM_COW(N-1)+NUM_COW(N-3)END SELECTEND FUNCTION NUM_COWPROGRAM COW_PROPARAMETER(N=20)WRITE(*,100)N,NUM_COW(N)100 FORMAT(5X,第,I3,年共有,I5,头牛)END运行结果是:第 20 年共有 1873 头牛例 8.33 有一个n级台阶的楼梯,上楼时可以一步跨一级、两级、三级。问登上这n级楼梯共有多少种跨级的方法?分析:本例

99、与例8.22类似,也是一个递推数列的问题,设A(n)表示n级楼梯的跨级方法数,显然有:A(1)=1 总共只有一种方法A(2)=2 共有一步跨两级(记为 2)和走两步一级(记为1,1)两种方法A(3)=4 共有(1,1,1),(1,2),(2,1),(3)等4种方法对于 n3,考虑上楼的最后一步有一级、两级、三级等三种不同的方法,对应最后一步跨三级,前面的n-3级有A(n-3)种方法;对应于最后一步跨两级,前面已有A(n-2)种方法;对应于最后一步跨一级,前面有A(n-1)种方法,根据组合学中的加法原理,有:A(n)=A(n-1)+A(n-2)+A(n-3)程序及运行实例如下:INTEGER R

100、ECURSIVE FUNCTION TOWER(N) RESULT(NUM_TOWER)SELECT CASE(N)CASE (1) NUM_TOWER=1CASE (2) NUM_TOWER=2CASE (3) NUM_TOWER=4CASE (4:) NUM_TOWER=TOWER(N-1)+TOWER(N-2)+TOWER(N-3)END SELECTEND FUNCTION TOWERPROGRAM TOWER_PROPARAMETER(N=20)INTEGER TOWERWRITE(*,100)N,TOWER(N)100 FORMAT(5X,I2,级楼梯共有,I10,种不同的跨级方法

101、)END PROGRAM TOWER_PRO运行结果是: 20 级楼梯共有 121415 种不同的跨级方法习题习题1.指出下列错误的语句函数定义:(1)F(X,Y)=X+Y+2+A-B(2)SUM(X(2),Y,Z)=3*Y+(X(2)+Z)*Z(3)F(X,Y,X)=X*2-Y+X+C-SIN(A)(4)X2(Z,Y(I)=EXP(Z+1)-A*Y(I)(5)LAN(A,B,C)=A*X+(B-C)*2-X*Y2.叙述数据公用语句COMMON 和共用存储单元语句EQUIVMENT之间的相似与不同点。3下列程序的运行显示结果是什么?(1)PROGRAM FIRST DIMENSION A(3,

102、3) DO I=1,3 DO J=1,3 A(I,J)=0 ENDDO ENDDO CALL P1(A)WRITE(*,100)A100 FORMAT(1,9F4.1)ENDSUBROUTINE P1(A)DIMENSION A(5)A(1)=1DO I=2,5 A(I)=A(I-1)+1ENDDOEND(2)PROGRAM TWO SUBROUTINE F1(A,B)X=2 B=3*A+4CALL F1(X,Z) B=F2(B)WRITE(*,100)Z END100 FORMAT(2,F8.2) FUNCTION F2(X)END F2=5*X+6 END(3)PROGRAM THREE

103、SUBROUTINE P2DIMENSION A(10) DIMENSION B(10)COMMON X,Y,A(10) COMMON P,Q,B(10)X=2.3 WRITE(*,100)P,Q,BY=-3.7 100 FORMAT(3,4F5.1)DO K=1,10 END A(K)=K+0.5ENDCALL P2END(4)PROGRAM FOUR SUBROUTINE P2COMMON A(10),/R1/W COMMON B(10),/R1/SREAD(*,100)A S=0CALL P2 DO I=1,10WRITE(*,200)W S=B(I)+S100 FORMAT(10F4.

104、1) ENDDO200 FORMAT(4,F7.1) ENDEND 5.设:设计一个计算S的函数子程序,并调用该函数子程序计算:6设计一个计算n! 的函数子程序,并调用该子程序计算数e的近似值。当 n!1E8时停止计算。计算公式是:7对已知自然数n,设计一个判断n是否为素数的子程序,并调用该子程序:(1)将100120共11个偶数分解为两个素数和的形式(2)用READ语句读入一个自然数n,对n进行素因子分解。要求使用函数子程序和子例行程序两种方法。8对任意自然数n,设计一个求n的各数位立方和的函数子程序F(n)(如F(121)=1*3+2*3+1*2=1+8+1=10),并调用F(n)求100

105、0以内的所有水仙花数(水仙花数的概念请参看例 8.5)。9自己设计一个求余函数MOD_SELF(M,N),功能与内在函数MOD相同(不能调用MOD函数。)10设计一个函数子程序,对于自然数m、n,该函数求m、n的最小公倍数。11设计一个函数子程序将一个数字型字符转化为一个与其相同的数值型数据,并调用该子程序完成:(1)将字符型数据23456 转化为整型数据23456 (2)将字符型数据 75.8转化为实型数据 75.8.12设计一个子例行程序,计算一个任意数组A中正数、负数和0的个数及其和。13设计一个子例行程序SORT(A,N,K),其中A是一个一维数组,N是A的元素个数,SORT的功能是:

106、 当K=1时,将数组A按升序排列;当K=0时,将数组A按降序排列;当K为其它数值时,数组A保持原序。14Ackermann函数的定义是:A(0,n)=n+1A(m,0)=A(m-1,1)A(m,n)=A(m-1,A(m,n-1)其中m、n是自然数,设计一个计算Ackermann的函数子程序,并计算A(5,5)的值。15设计一个函数子程序line(z1,z2,z3),参数z1、z2、z3是复数,代表平面上三个点,当三个点共线时,函数值为1,否则为0。16设计一个计算三阶行列式值的函数子程序。17对于任意的二维数组A(m,n),设计一个子例行程序max(A,B,m,n,k)。其中A是一个二维数组,

107、m、n分别是A的行数和列数,B是一个一维数组。子程序的功能是:当参数k=1时,求A的每列上的最大元素并存放到B(1)、B(2).B(n)中;当参数k=2时,求A每行上的最大元素并存放到B(1)、B(2).B(m)中。18设计一个子例行程序,将一个字符型数据翻译成密文,翻译规则是:(1)当对应字符是一个英文字母时,将AZ(az),BY,CX.(2)当对应字符非英文字母时,保留该字符原文。如将字符型数据word!应翻译为dliw!19设计一个矩形方法计算函数定积分的函数子程序。矩形积分公式是:式中h=(b-a)/n,即将积分区间a,b划分为n个等长的区间,n是小区间的个数,而h是小区间的长度。20设计一个生成(0,1)中随机数的函数子程序。21有52张扑克牌排列为一行,并用152给每张扑克牌编号。首先将全部扑克牌正面朝上并按下列操作翻转扑克牌(即将原来正面朝上的翻转为正面朝下,将原来正面朝下扑克牌的翻转为正面朝上) 。 (1)第一轮将2的倍数位置上的扑克全部翻转。(2)第二轮将3的倍数位置上的扑克牌全部翻转,.。(3)重复上述过程直到最后一轮将编号为52的扑克牌翻转。设计一个递归子例行程序模拟上述过程,并指出最后正面朝上的扑克牌位置。

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 工作计划

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号