N=3 !现在N=(/1,2,3,2,5,2,7,2,3/) ELSEWHERE(MOD(N,5)==0)
N=5 !现在N=(/1,2,3,2,5,2,7,2,3/) ELSEWHERE
N=0 !现在N=(/0,2,3,2,5,2,0,2,3/) END WHERE
下面说明WHERE结构的用法:
● 一个结构名称不能单独出现在初始WHERE语句,或END WHERE语句里,必须成对出现。如果一个结构名称出现在ELSEWHERE语句里,或者是过滤ELSEWHERE语句里,那么它也必定出现在WHERE结构语句里。
● 在WHERE结构的每个赋值语句里,被定义的变量必须和过滤网具有相同的形状,如果在WHERE结构的其他位置也出现了过滤网,它们的形状必须都相同。 ● WHERE结构里的语句按照其出现的顺序执行。
● 每个过滤网的有效取值只有一次,随后的逻辑表达式里的取值变化都对控制过滤网的值没有影响。
● WHERE结构里的自定义赋值必须由基本子例行程序定义。
● 只有在控制过滤网取真值时,赋值语句里的基本运算或函数才得到计算。 【例9-12】
REAL X(1,100) …
WHERE(X>0.0) SQRTX=SQRT(X) END WHERE
● 如果在结构的逻辑表达式或赋值语句当中出现了数组构造器,那么它将不经过过滤而得到完全计算。
● 结构里的表达式或变量或逻辑表达式里的非基本函数引用将得到完全计算,尽管有可能结果数组的所有元素都用不上。 【例9-13】
REAL A(2,3),B(3,10),C(2,10),D(2,10) IMTRINSIC MATMUL …
WHERE (D<0.0) C=MATMUL(A,B) END WHERE
其中矩阵乘积的所有元素都得到了,但是只有小于0的元素才得到赋值。 ● 在WHERE结构里,只有WHERE语句才能成为分支目标。
9.4.3 WHERE结构的运行
当WHERE结构开始运行的时候,其中的控制过滤网和候选过滤网就都已经建立了,而控制过滤网主宰了随后的语句块的执行。
● 如果WHERE结构不是嵌套WHERE结构,那么控制过滤mask取得逻辑表达式的值,而候选过滤网的值为.NOT.mask。 【例9-14】
WHERE(A1) !语句1 CALL B1 !块1 ELSEWHERE(A2) !语句2 CALL B2 !块2 ELSEWHERE !语句3 CALL B3 !块3 END WHERE
在执行语句1之后,控制过滤网的值为A1,而候选过滤网的值为.NOT.A1;
在执行语句2之后,控制过滤网的值为(.NOT.A1).AND.A2,而候选过滤网的值为(.NOT.A1).AND(.NOT..A2);
在执行语句3之后,控制过滤网的值为(.NOT.A1).AND(.NOT..A2)。
● 如果WHERE结构是嵌套WHERE结构,还是以上面的例子来说明运行过程:如果最外层主宰着块内的语句运行的初始控制过滤网是outer-mask,那么块1的控制过滤网取值为outer-mask.AND.A1,从这个初始状态开始,就可以得到向内嵌套过程的每个控制过滤网取值,即总是向内取逻辑与运算。到运行内部END WHERE语句时,控制过滤网就回复到outer-mask。
9.4.4 WHERE结构与控制结构的差别
WHERE结构与控制结构的主要差别在前面9.4已经讨论过,除此之外,还有个差别,就是在WHERE结构里,不存在从WHERE块或ELSEWHERE块里转移出来的机制,当然除了使用函数引用之外。因为在这些块里都不允许分支语句。
WHERE结构还有一个特征,就是在结构前面块里的语句的执行,会影响后面块里的变量引用,因为所有块里的语句都会顺序得到执行。
9.5 并行指标数组赋值
在数学计算当中,经常会遇到如下的计算任务:
xij?i2?j2,对于i从1到n,j从1到m。
xii?yi,对于i从1到n。
其中第一个计算可以使用嵌套DO循环描述如下:
DO J=1,M DO I=1,N X(I,J)=I**2-J**2 END DO END DO
不过这种实现方法完全没有利用数组这种强大的数据结构,而在很多系统里面,通过利用数组,可以更加有效地完成上面类型的计算任务。
对于FORTRAN而言,除了运用DO循环之外,运用固有函数SPREAD,再采用数组赋值的形式,也可以完成上面的计算:
X=SPREAD((/(I,I=1,N)/),DIM=2,NCOPIES=M)**2-& SPREAD((/(I,I=1,M)/),DIM=1,NCOPIES=N)
而在FORTRAN里,一种更加自然的计算方法是使用FORALL语句。该语句充分发挥了数组在数据结构方面的特点,使得这种计算更加有效率:
FORALL (I=1:N,J=1:M)X(I,J)=I**2-J**2
显然,在这种计算方法里面,FORALL能够直接把数组元素和片断引用到表达式里面,不仅使得计算过程一目了然,而且表现了并行计算的优越性。
对于上面的第二个数学计算任务,它不能使用数组片断来描述,但FORALL语句则能够把秩为1的数组Y的元素赋值给数组X的对角线:
FORALL(I:N)X(I,I)=Y(I)
如此就轻松自然地完成了计算任务。
在关键词FORALL后面的括号部分称为FORALL头,它能够对后面的多个语句发挥控制作用。
【例9-15】
FORALL (I=2:N-1,J=2:N-1)
A(I,J)=(A(I+1,J)+A(I-1,J)+A(I,J+1)+A(I,J-1))/10.0 B(I,J)=10.0/A(I+1,J+1) END FORALL
在FORALL语句与END FORALL语句之间的部分,称为FORALL体,FORALL体里面可以包含如下内容:
● 赋值语句; ● 指针赋值语句; ● WHERE结构和语句; ● FORALL结构和语句。
FORALL体可以包含FORALL结构和语句,也就是说FORALL结构可以嵌套。
FORALL体的结构和语句的执行是顺序往下执行的,所有右边的表达式对所有的指标进行求值计算时,对于不同的指标的求值计算,则是按照任意次序,当这样的计算都完成之后,随即进行的赋值也是按照任意的次序。
所以尽管FORALL语句构造了一个循环结构,但是每当针对结构里的一个语句进行求值时,被认为是进行并行指标运算,每完成一个语句的所有指标的运算,才转到下一个语句的计算,因此具体的在计算每个语句的所有指标时,到底系统是按照什么顺序,是不需要规定的,完全依靠具体的系统的自身特定来实现,在FORTRAN语言层面上不加以规定,因此使得FORALL结构具有了与控制结构完全不同的特征,因为所谓控制结构,是对每一个指标的运算都加以控制的,因此在执行控制语句时,不得不制定不同指标的运算顺序。
FORALL的优越性正是体现在这里,因为语言没有规定的对指标的计算,完全可能在某些系统里面是并行进行的,这样的话,一下子就使得数组具有了并行计算的特征,从而可以大大地提高程序运行的效率。
有时,可能需要排除一些元素,这时,就需要在FORALL头里加入一个过滤表达式。 【例9-16】
FORALL(I=1:N,J-=1:M,A(I)<100.AND.B(I)<100)& C(I,J)=A(I)+B(J)
9.5.1 FORALL结构
在FORALL头里的说明三项列,再加上可选的过滤网,就可以控制FORALL体内的多种赋值语句,WHERE结构与语句,以及嵌套FORALL语句与结构。
下面我们分形式与运行两个部分来讨论FORALL结构。 1. FORALL结构的形式
FORALL结构的句法形式(R747)为:
[forall-construct-name:]FORALL(forall-triplet-specification-list & [,scalar-logical-expression]) [forall-body-construct]…
END FORALL [forall-construct-name]
其中的forall说明三项(forall-triplet-specification)的句法形式(R750)为:
index-name = scalar-integer-expression:&
scalar-integer-expression [:scalar-integer-expression]
其中的forall体结构的句法形式(R751)为:
assignment-statement pointer- assignment-statement where-construct where-statement forall-construct forall-statement