Fortran 嵌套 WHERE 语句

rgr*_*run 5 fortran nested where fortran90

我有一个带有嵌套 WHERE 语句的 Fortran 90 源代码。有一个问题,但似乎很难理解到底发生了什么。我想把它转换成DO-IF结构以便调试。我不清楚的是如何翻译嵌套的 WHERE。

所有数组都具有相同的大小。

WHERE (arrayA(:) > 0)
    diff_frac(:) = 1.5 * arrayA(:)
    WHERE (diff_frac(:) > 2)
        arrayC(:) = arrayC(:) + diff_frac(:)
    ENDWHERE
ENDWHERE
Run Code Online (Sandbox Code Playgroud)

我的选项A:

DO i=1, SIZE(arrayA)
  IF (arrayA(i) > 0) THEN
    diff_frac(i) = 1.5 * arrayA(i)
    DO j=1, SIZE(diff_frac)
      IF (diff_frac(j) > 2) THEN
          arrayC(j) = arrayC(j) + diff_frac(j)
      ENDIF
    ENDDO
  ENDIF
ENDDO
Run Code Online (Sandbox Code Playgroud)

我的选项B:

DO i=1, SIZE(arrayA)
  IF (arrayA(i) > 0) THEN
    diff_frac(i) = 1.5 * arrayA(i)        
    IF (diff_frac(i) > 2) THEN
        arrayC(i) = arrayC(i) + diff_frac(i)
    ENDIF        
  ENDIF
ENDDO
Run Code Online (Sandbox Code Playgroud)

谢谢

roy*_*vib 4

根据 comp.lang.fortran 中的线程“嵌套 WHERE 构造”(特别是 Ian\ 的回复),问题中的第一个代码似乎翻译为以下内容:

\n
do i = 1, size( arrayA )\n    if ( arrayA( i ) > 0 ) then\n        diff_frac( i ) = 1.5 * arrayA( i )\n    endif\nenddo\n\ndo i = 1, size( arrayA )\n    if ( arrayA( i ) > 0 ) then\n        if ( diff_frac( i ) > 2 ) then\n            arrayC( i ) = arrayC( i ) + diff_frac( i )\n        endif\n    endif\nenddo\n
Run Code Online (Sandbox Code Playgroud)\n

除了第二个掩码部分(见下文)之外,这与马克的回答几乎相同。F2008文件的主要摘录如下:

\n
\n

7.2.3 掩码数组赋值 \xe2\x80\x93 WHERE(第 161 页)

\n

7.2.3.2 掩码数组赋值的解释(第 162 页)

\n

... 2. WHERE 构造中的每个语句都按顺序执行。

\n

... 4. mask-expr最多计算一次。

\n

... 8. 在执行属于where-body-construct一部分的 WHERE 语句时,控制掩码被建立为具有值 m_c .AND。掩码表达式

\n

... 10. 如果基本操作或函数引用出现在where-assignment-stmtmask-exprexpr变量中,并且不在非基本函数引用的参数列表内,则执行该操作或该函数仅针对与控制掩码的真实值相对应的元素进行评估。

\n
\n

如果我正确理解上述线程/文档,则条件diff_frac( i ) > 2在 后求值arrayA( i ) > 0,因此对应于双 IF 块(如果我假设A .and. B在 Fortran 中未指定求值顺序)。

\n
\n

但是,正如上面线程中所述,实际行为可能取决于编译器...例如,如果我们使用 gfortran5.2、ifort14.0 或 Oracle fortran 12.4(不带选项)编译以下代码

\n
integer, dimension(4) :: x, y, z\ninteger :: i\n\nx = [1,2,3,4]\ny = 0 ; z = 0\n\nwhere ( 2 <= x )\n   y = x\n   where ( 3.0 / y < 1.001 )  !! possible division by zero\n      z = -10\n   end where\nend where\n\nprint *, "x = ", x\nprint *, "y = ", y\nprint *, "z = ", z\n
Run Code Online (Sandbox Code Playgroud)\n

他们都给出了预期的结果:

\n
x =            1           2           3           4\ny =            0           2           3           4\nz =            0           0         -10         -10\n
Run Code Online (Sandbox Code Playgroud)\n

但是如果我们使用调试选项进行编译

\n
gfortran -ffpe-trap=zero\nifort -fpe0\nf95 -ftrap=division  (or with -fnonstd)\n
Run Code Online (Sandbox Code Playgroud)\n

gfortran 和 ifort 通过在掩码表达式中求值而中止浮点异常y(i) = 0,而 f95 运行时没有任何抱怨。(根据链接的线程,Cray 的行为与 gfortran/ifort 类似,而 NAG/PGI/XLF 与 f95 类似。)

\n
\n

附带说明一下,当我们在 WHERE 构造中使用“非元素”函数时,控制掩码不适用,所有元素都用于函数求值(根据上述草案的第 7.2.3.2 节第 9 句)。例如下面的代码

\n
integer, dimension(4) :: a, b, c\n\na = [ 1, 2, 3, 4 ]\nb = -1 ; c = -1\n\nwhere ( 3 <= a )\n    b = a * 100\n    c = sum( b )\nendwhere\n
Run Code Online (Sandbox Code Playgroud)\n

给出

\n
a =  1 2 3 4\nb =  -1 -1 300 400\nc =  -1 -1 698 698\n
Run Code Online (Sandbox Code Playgroud)\n

这意味着 sum( b ) = 698 是从 b 的所有元素中获得的,两个语句按顺序求值。

\n