替换Fortran 95及更高版本中过时的“语句函数”?

时间:2017-08-30 11:57:37

标签: function macros fortran fortran95

原始问题

据我了解,自Fortran 95声明函数已被宣布为过时而支持内部函数。但是,内部函数不包括所有用例,特别是当使用语句函数作为隐含参数的缩写时,使得长公式的实现更具可读性。这个用例是否有足够的替代品?

实施例

例如,假设我们有关系

Cᵢⱼ=∫dx1∫dx2∫dx3∫dy1∫dy2∫dy3(AᵢⱼBᵢⱼ+BᵢⱼAⱼᵢ)

E.g。将直接使用A,B的内部表示的实现与先前代码强制执行的索引顺序进行比较,得到

do a1=1,NGRID1; do a2=1,NGRID2; ...; do aN=1,NGRIDN
  x(i,j) = x(i,j) &
      & + ARR_A(x1,x2,x3,i,y1,y2,y3,j)*ARR_B(x1,x2,x3,i,y1,y2,y3,j) &
      & + ARR_B(x1,x2,x3,i,y1,y2,y3,j)*ARR_A(x1,x2,x3,i,y1,y2,y3,j)
end do; end do; ...; end do

使用语句函数作为缩写

的实现
A(i,j) = ARR_A(x1,x2,x3,i,y1,y2,y3,j)
B(i,j) = ARR_B(x1,x2,x3,i,y1,y2,y3,j)
...
do x1=1,NGRID1; do x2=1,NGRID2; ...; do y3=1,NGRIDN
  x(i,j) = x(i,j) + A(i,j)*B(i,j) + B(i,j)*A(i,j)
end do; end do; ...; end do

在第二个版本中,在注意到 出现问题后,更容易发现索引的混合uo顺序。

使用宏?

我发现实现类似语义的唯一方法是使用预处理器宏。通常,使用C风格的宏,这将导致

#define A(i,j) ARR_A(x1,x2,x3,i,y1,y2,y3,j)

但这会牺牲名称的范围。虽然这似乎有用,特别是当多个函数使用相同的缩写时,它似乎可能相当混乱。首先,当使用语句函数时,编译器将提供更多有用的错误消息,而不是宏。

如果我们想在不同的上下文中为不同的事物重用相同的名称,它还需要手动#undefine名称。

解决方案(1)

我误解了CONTAINS和内部函数的工作原理(参见IanH's answer及其评论)。

简短:内部函数可以在CONTAINS的子程序中定义,并且与语句函数完全相同,但语法更详细。

误解的产生部分是因为它显然是允许以这种方式在子程序中定义子程序。显然它确实有效。不知道我做错了什么。

1 个答案:

答案 0 :(得分:4)

内部过程几乎是这个用例的语句函数的替代品,它们通常具有更多功能和更少错误倾向的好处,但代价是它们的定义有些轻微的额外冗长。

MODULE some_module     ! Just for the sake of example.
  ...
CONTAINS
  ! The host of the internal procedure.  This could 
  ! also be an external procedure or a main program.
  ! It could also be a function.
  SUBROUTINE some_subroutine
    ...
    DO i = 1, 3
      DO j = 1, 3
        DO x1 = 1, 3
          DO x2 = 1, 3
            ...
            x(i,j) = x(i,j) + A(i,j)*B(i,j) + B(i,j)*A(i,j)
            ...
          END DO
        END DO
      END DO
    END DO     
    ...      
  CONTAINS
    ! An internal procedure.  For different use cases 
    ! this could also be a subroutine.
    FUNCTION A(i,j)
      INTEGER, INTENT(IN) :: i,j
      REAL :: A
      A = ARR_A(x1,x2,x3,i,y1,y2,y3,j)
    END FUNCTION A

    FUNCTION B(i,j)
      INTEGER, INTENT(IN) :: i,j
      REAL :: B
      B = ARR_B(x1,x2,x3,i,y1,y2,y3,j)
    END FUNCTION B
    ...
 END SUBROUTINE some_subroutine
 ...
END MODULE some_module

请注意,Fortran 77/90/95/2003规则下的最大阵列等级为7。

相关问题