FORTRAN语言题解及分析

Author: 苏民生 教授 Date: 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