FORTRAN语言题解及分析 苏民生 教授 1994-07-08 阅读下列程序说明和FORTRAN程序,把应填入其中空白 处的字句,写在答卷的对应栏内。 [程序说明] 本程序按泰勒展开式计算Sin X的近似值。Sin X的泰勒展开式为 SinX=x_/_1! - x3_/__3! + x5_/__5! - x7_/__7! + …= 计算精度为10-6。程序中T用来存放泰勒展开式中的一项。 [程序] EPS=1E-6 READ(*,5)X 5 FORMAT(F5.2) SINX=0.0 T=X N=1 10 IF( (1) )THEN SINX=(2) N=N+1 T=(3) (4) (5) WRITE(*.20)X,SINX 20 FORMAT(1X,'SIN(',F5.2,')=',F14.6) STOP END [答案] (1) ABS(T).GE.EPS或ABS(T).GE.1E-6 (2)SINX+T (3)-T*× *× /(2.0*N-2.0)/(2.0*N-1.0) (4)GOTO 10 (5)ENDIF [分析] 本题是级数求和问题,应当由一个循环完成求和动作,而在循环之前为预置动值,在循环之后输出结果。由程序可知,该循环应由块IF结构和有关语句构成,(5)应为块IF结构终结语句ENDIF,而(4)应当是GOTO 10,以构成while-do循环结构。 (1)是需要继续循环的条件。由程序说明,计算时要求累加项T有T>=10-6,而舍去 T<10-6的项T。由此,(1)应为ABS(T).GE.EPS,也可以是ABS(T).GE.E-6。如果不用函数ABS,可以是(T.GE.EPS).OR.(T.LE.-EPS)。 (2)是累加和SINX+T。 (3)是新项表达式,由展开式前后项关系,应有T=-T*× *× /(2.0*N-2.0)/(2.0*N-1.0) 注意由(4)、(5)构成的while-do结构,也可以将(4)写为ENDIF,而将(5)写成IF(ABS(T).GE.EPS)GOTO 10,但这种写法使块IF的判断与逻辑IF的判断重复,并不好。 试题二(程序员级下午试题十) 阅读程序 [程序说明](略) [程序] SUBROUTINE EXEC(A,M,N,OP,OPE1,OPE2,OPE3,L) REAL A(M,N,B(1000) INTEGER OPE1(L),OPE2(L),OPE3(L) CHARACTER OP(L),CH DO 10 I=1,L K=OPE3(I) (1) IF (CH.EQ.'I')THEN WRITE(*.*)'A(',MOD(K-1,M)+1,',',(K-1)/M+1,')=' READ(*.*)(2) ELSEIF (CH.EQ.'+') THEN B(K)=(3) ELSEIF (CH.EQ.'-') THEN B(K)=(4) ENDIF CONTINUE K=1 DO 20 J=(5) DO 20 I=(6) (7)=B(K) K=K+1 RETURN END [答案] (1) CH=OP(I) (2) B(K)或 B(OPE3(I) (3) B(OPE1(I))+B(OPE2(I)) (4) B(OPE1(I))-B(OPE2(I)) (5)1,N 或1,N,1 (6) 1,M 或1,M,1 (7) A(I,J) [分析] 程序说明非常详细。子程序EXEC的功能是依据输入数据OP、OPE1、OPE2和OPE3,最终求出数组A,从而完成通用表格计算任务。OP(I)、OPE1(I)、OPE2(I)和OPE3(I)是程序说明中最后一个表中的一行数据,代表了 条计算指令。数组B是中间工作数组,B(1),B(2),B(3),……分别对应于A(1,1),A(2,1),A(3,1),……(A元素按先列后行顺序编号),子程序中先求出B,再求A。 观察程序结构,EXEC的执行部分可分为上、下两块。下块由相嵌两层DO循环构成,应是由B元素值求出A元素值,(7)是传送目的地,应为A(I,J),由“先列后行编号”,(5)应为1,N(可为1,N,1),(6)应为1,M(可为1,M,1)。 EXEC前面一块由外层DO循环和内层块IF结构组成,应是产生B元素值的处理过程。在块IF中的判断条件用到变量CH,其值应是指令操作符,应在使用前对CH赋值,因此,(1)应为CH=OP(I)。 (2)是操作符为'I'时读入数据应存入的目的地,它应是相应的B元素之值,(2)应填入B(K)或B(OPE3(I))。 (3)、(4)是加法或减法指令中产生和或差的表达式,应当是两个操作数之和或差。由程序说明,OPE1(I)、OPE2(I)等用于指明表元位置,它们不是操作数,表元值才是操作数。OPE1(I)、OPE2(I)等则相当于操作数的“地址”,(因此,程序说明中将OPE1等称为“操作数”,是不确切的。)操作数则应是相应表元值B(OPE1(I)),B(OPE2(I))等。由此,(3)应为B(OPE1(I))+B(OPE2(I)),(4)应为B(OPE1(I))-B(OPE2(I)) 试题三(程序员级下午试题十五) 阅读下列程序说明和FORTRAN程序,把应填入其中空白处的字句,写在答卷的对应栏内。 [程序说明] 欧·乔·马特里克(I·J·MATRIX)博士在十进制数中发现了一组有趣的公式序列: 9×1+2=11 9×12+3=111 9×123+4=1111 … … 9 12345678+9=111111111 我们称10进制数的基为10。同样,对 B(B=2,3, ……)进制数来说,其基为B。本程序对任一基 B(3≤B≤10)是否存在上述性质的公式加以验证。例如 4进制中的公式序列为: 3×1+2=11 3×12+3=111 值得注意的是,这些公式都必须用B进制运算规则计算。 若把公式记为X×Y+Z=W,则程序中X和Z存放在整型变量中,Y和W分别存放在数组N和M中,每个数组元素存放Y或W的一位数字,其中N(1)和M(1)分别存放Y和W的低位数字。 子程序MUL用来实现数组N中的数与整数J相乘,其乘积存贮在数组M中。其中NUM表示N中数的位数,IB为数制的基。子程序ADD用来实现数组M中的数与整数J相加,其和存贮在数组M中,其中NUM和IB的含义同上。 [程序] INTEGER B,N(100),M(100) (1) READ(*,*)B  FLAG=.TRUE.  DO 20 I=1, (2) DO 30 J=1, I 30 N(J)=I+1-J CALL MUL(N,M,B-1,I,B) CALL ADD ( (3) ) DO 60 K=1,I+1 IF(M(K).NE.1) (4) 60 CONTINUE 20 CONTINUE IF (FLAG) THEN WRITE(*,*)'OK.' ELSE WRITE(*,*)'ERROR' ENDIF STOP END SUBROUTINE MUL(N,M,J,NUM,IB) DIMENSION N(NUM),M(NUM+1) DO 5 I=1,NUM+1 5 M(I)=0 IC=0 DO 10 I=1,NUM NN=N(I)*J+IC (5) 10 M(I)= (6) (7) RETURN END SUBROUTINE ADD(M,J,NUM,IB) DIMENSION M(NUM) (8) DO 10 I=1,NUM IF (M(I).GE.IB) THEN M(I)=M(I)-IB M(I+1)=M(I+1)+1 ENDIF 10 CONTINUE RETURN END [答案] (1) LOGICAL FLAG (2) B-2 (3) M, I+1, I+1, B (4) FLAG=.FALSE. (5) IC=NN/IB 或IC=(N(I)*J+IC)/IB (6) MOD(NN,IB) 或NN-NN/IB*IB 或NN-IC*IB (7) M(I)=IC 或M(NUM+1)=IC (8) M(1)=M(1)+J 试题三[分析] 本题程序由3个程序单位组成。主程序验证给定公式左式X*Y+Z之值是不是“全1”,并给出验证结果,输出OK或ERROR。计算X*Y时调用子程序MUL,该乘积与之相加时调用另一个子程序ADD。 主程序中使用变量FLAG标志验证结果,它取值为.TRUE.或.FALSE.,是逻辑变量,应在使用之前说明,因此,(1)应当是类型语句LOGICAL FLAG。而(4)是当存放左式计算结果某一位数值不等于1时的处理,此情况表明验证结果是否定的,与后两块IF的的输出参照,此处应为FLAG=.FALSE.。 (2)作为I的上界值,决定于数制基数B。在说明中,当B=10时右式数字1的数目依次为2,3,4,…,9,此时I值应依次为1,2,…,8,因此(2)应为B-2。 调用MUL计算X*Y之后,调用ADD计算乘积与Z之和。由说明,Z值为2,3,…,即应为I+1。X*Y已存放在数组M各元素中,与Z相同后得到的各位数字仍放在M各元素中。(3)是调用ADD时的实参表,与形参表相对应。形参J应是相加的整数,对应实参为I+1。NUM是数组M原来实有的元素数目,即X*Y乘积的位数,对应实参也应是I+1。IB是数制基数,对应实参应为B。因此,(3)应为M,I+1,I+1,B。 子程序ADD中,(8)之后是对于M(I)的进位处理,表示与J相加的操作应在(8)进行,J应加到表元最低位M(1)中,应填写为M(1)=M(1)+J。至于是否M(1)需要进位,以后如果低位有进位高位是否随之需要进位,则由后面DO循环完成。 现在还有三处填空都在子程序MUL中。这个程序是将数组N表示的IB进制数乘以整数J,乘积的各位数字放在数组M元素中。子程序中变量IC应是进位值,J每和N(I)相乘之后都要考虑到是否进位,(5)应为求进位值的赋值语句IC=NN/IB(整除),(6)则应是从NN中去掉进位值的表达式MOD(NN,IB),或写或NN-IC*IB。(7)在DO循环之后,此时下标最大的M元素应存入进位值,(7)应为M(I)=IC,也可以是M(NUM+1)=IC,但不应是M(I+1)=IC 试题四(高级程序员级下午试题九) 填空 [程序说明] 本程序是一个财务科目汇总的子程序。 科目编号用三位无符号整数表示,例如现金科目的编号为100,则100.1,100.2就是它的二个子目录。而100.1.1是子科目100.1的子科目。本程序中假定一个科目最多有三层子科目。 子程序中,数组SUBJ(4,L)用来存放科目编号,L是系统中科目和子科目的总数(假定L1000)。 规定在数组SUBJ中父科目编号必须位于它的子目录编号之前。子程序中,逻辑数组LD(L)存放相应的科目或子科目的借、贷方类型,.TRUE.表示贷方,.FALSE.表示借方。数组A(L)存放相应科目金额。数组SUBJ、LD和A的值由调用程序提供。其中位于叶结点上的子科目金额已存放在数组A中的相 应位置上,A中其他位置上的值已置为0.0。 子程序中,数组FATHER用记录相应子科目的父科目在SUBJ中的位置(列下标),供汇总时使用。规定对 应于科目的FATHEER元素的值为0。 [程序] SUBROUTINE RESUME(L,SUBJ,J,A,LD) INTEGER SUBJ(4,1),FATHER(1000) REAL A(L) LOGTCAL LD(L) DO 20 I=L,1,-1 FATHER(I)=0 IF (SUBJ(2,I).EQ.0) GOTO 20 DO 30 LEN=4,1,-1 IF (SUBJ(LEN,I).NE.0) GOTO 40 30 CONTINUE 40 DO 50 K=I-1,1,-1 IF (1) THEN DO 60 M=1,LEN-1 IF (SUBJ(M,I).NE.SUBJ(M,K))(2) 60 CONTINUE (3) ENDIF 50 CONTINUE 65 FATHER(I)=K 20 CONTHER DO 70 I=L,1,-1 (4) IF (K.NE.0) THEN IF (5) THEN A(K)=A(K)+A(I) ELSE (6) ENDIF ENDIF 70 CONTINUE RETURN END [答案] (1) SUBJ(LEN,K).EQ.0 (2) GOTO 50 (3) GOTO 65 (4) K=FATHER(I) (5) LD(K).EQU.LD(I) (6) A(K)=A(K)-A(I)? 试题四分析程序说明详细描述了子程序RESUME所执行的金额“汇总”的意义,以及子程序中变量L、数组SUBJ、LD、A和FATHER的意义,而对于处理过程却没有直接说明,需要通过阅读说明和程序分析出来。 子程序中的数组SUBJ,内容如说明中表中的内容,为4行L列矩阵,每一列表示一个科目或子科目的编号。数组A则提供每个科目或子科目的金额,做为输入值,只提供叶结点科目金额,并在子程序执行后求出其它结点(科目或子科目)金额。 由程序说明,计算每个不是叶结点的科目或子科目的金额时,是求其下一级各结点金额 的代数和。子程序中使用数组FATHER则意味着上述统计是“自下而上”的,即从XUBJ的最后一列依次向前,将每一子科目的金额 加到它的父科目上。 现在来看程序,其执行部分分为上下两块,前一块(从DO 20……到 20 EONTINUE)对于I(取值从L,L-1,……,直至1)求出FATHER(I),后块(从DO 70……到70 CONTINUE)根据FATHER(I)值进行汇总。 在后块中,(6)应为A(K)=A(K)-A(I),与上面A(K)=A(K)+A(I)相对应,分别处理汇总时相加(同为借方或贷方)及相减(一方为借方,一方为贷方)的问题。某一方是借或贷用LD元素标志,因此,条件(5)应为LD(I).EQU.LD(K)。(4)应给出后面所用的K值,它应是I对应的父结点编号,(4)应定为K=FATHER(I)。 子程序的前块确定FATHER(I)值。它是由内层循环(从DO 50 K=I-1,1,-1到50 CONTINUE)进行搜索的,前3个空也恰好在这个内层循环中。最内层循环(从DO 60……到60 CONTINUE)是比较SUBJ第I列和第K列同一行元素(从第I至第LEN-1行是否相等,如都相等,则第I列是第K列子结点,即第K列是第I列子结点,否则,只要有一处不相等,就没有上述父子结点关系。由此,(2)应为GOTO 50(继续考察下一个第K列),而(3)应跳出K循环,认定当前K值即为所求父结点科目(子科目)列号,应填入GOTO 65。(1)是对于第K列进一步考察的条件,它要求第K列有可能是第I列的父结点。此时已知SUBJ(LEN,I)是第I列中行下标最大的非零元素,而程序说明指出其父结点的第LEN行下标应当为0,即如果第K列SUBJ元素是所寻找的父结点,必须有SUBJ(LEN,K)为0,因此(1)应填写为SUBJ(LEN,K)。EQ。O