根据comp.lang.fortran中的帖子
"嵌套WHERE结构(特别是Ian的回复),似乎问题中的第一段代码翻译为以下内容:
do i = 1, size( arrayA )
if ( arrayA( i ) > 0 ) then
diff_frac( i ) = 1.5 * arrayA( i )
endif
enddo
do i = 1, size( arrayA )
if ( arrayA( i ) > 0 ) then
if ( diff_frac( i ) > 2 ) then
arrayC( i ) = arrayC( i ) + diff_frac( i )
endif
endif
enddo
这与Mark的答案几乎相同,除了第二个掩码部分(见下文)。 F2008 文档中的关键摘录如下:
7.2.3 掩码数组赋值 - WHERE (第161页)
7.2.3.2 掩码数组赋值的解释 (第162页)
... 2. WHERE 构造中的每个语句按顺序执行。
... 4. mask-expr 最多计算一次。
... 8. 在执行作为 where-body-construct 的 WHERE 语句时,控制掩码被确定为具有值 m_c.AND.mask-expr。
... 10. 如果 where-assignment-stmt 的 expr 或 variable 中或 mask-expr 中出现元素操作或函数引用,并且不在非元素函数引用的参数列表中,则该操作仅对控制掩码的 true 值所对应的元素执行或评估该函数。
如果我正确理解上述线程/文档,那么条件
diff_frac( i ) > 2
在
arrayA( i ) > 0
之后被评估,因此对应于双重IF块(如果我假设Fortran中的
A .and. B
不指定评估顺序)。
然而,正如上述线程中所提到的,实际行为可能取决于编译器...例如,如果我们使用gfortran5.2、ifort14.0或Oracle fortran 12.4(没有选项)编译以下代码。
integer, dimension(4) :: x, y, z
integer :: i
x = [1,2,3,4]
y = 0 ; z = 0
where ( 2 <= x )
y = x
where ( 3.0 / y < 1.001 ) !! possible division by zero
z = -10
end where
end where
print *, "x = ", x
print *, "y = ", y
print *, "z = ", z
它们都给出了预期的结果:
x = 1 2 3 4
y = 0 2 3 4
z = 0 0 -10 -10
但是如果我们使用调试选项进行编译
gfortran -ffpe-trap=zero
ifort -fpe0
f95 -ftrap=division (or with -fnonstd)
当在掩码表达式中求解y(i) = 0
时,gfortran和ifort通过浮点异常而中断,而f95则毫无怨言地运行。(根据链接的线程,Cray的行为类似于gfortran/ifort,而NAG/PGI/XLF类似于f95。)
作为一个附注,当我们在WHERE语句中使用“非元素”函数时,控制掩码不适用,所有元素都会在函数评估中使用(根据上述草案第7.2.3.2节第9句)。例如,以下代码:
integer, dimension(4) :: a, b, c
a = [ 1, 2, 3, 4 ]
b = -1 ; c = -1
where ( 3 <= a )
b = a * 100
c = sum( b )
endwhere
提供
a = 1 2 3 4
b = -1 -1 300 400
c = -1 -1 698 698
这意味着从b的所有元素中获得sum(b) = 698,两个语句按顺序执行。
where
实际上是在外部where
掩码所识别的单个元素上操作的if
块。这应该使转换为do
很容易,而且似乎你的“选项 B”是正确的。为什么标准允许这种模棱两可的结构而不直接使用if
是一个好问题。 - agentp