通过重构if语句/ do循环来避免重复代码

时间:2018-11-13 20:38:55

标签: performance if-statement fortran

嗨,我想在网格中许多不同的空间点上对函数施加特定条件。但是,我正在复制大量代码,并且效率越来越低。

如何仅通过使用do循环来执行我需要做的事情?我要在函数上施加的特定条件在所有不同的空间点都相同,因此我认为有一种方法可以在单个循环中完成所有这些操作。或者如何将所有这些If / else if语句合并为一个语句?必须有比我正在做的事更有效的方法。

我在下面提供了示例代码。

FUNCTION grad(psi)
IMPLICIT NONE
INTEGER :: i,j,kk,ll
INTEGER, PARAMETER :: nx = 24, ny = 24
COMPLEX,DIMENSION(3,3,-nx:nx, -ny:ny) :: psi, grad
REAL :: pi
REAL :: f0
INTEGER :: nxx, nyy

nxx = nx/2
nyy = ny/2

pi = 4*atan(1.0)
f0 = pi**2*1.3

DO i=-nx+1,nx-1 !spatial points
DO j=-ny+1,ny-1 !spatial points

   IF ( i == 0 .AND. j == 0 .AND. i == j) THEN ! I have lots of statements like this

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

    ELSE IF ( i == nxx .AND. j == nyy .AND. i == j) THEN ! I have lots of statements like this

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

  ELSE IF ( i == -nxx .AND. j == -nyy .AND. i == j) THEN ! I have lots of statements like this

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

   ELSE IF ( i == nxx .AND. j == -nyy) THEN ! I have lots of statements like this

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

   ELSE IF ( i == -nxx .AND. j == nyy) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

  ELSE IF ( i == nxx .AND. j == ny) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

  ELSE IF ( i == -nxx .AND. j == ny) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

   ELSE IF ( i == nx .AND. j == -nyy) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

   ELSE IF ( i == nx .AND. j == nyy) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

    ELSE 

        DO kk=1,3

        grad(kk,1,i,j)  = psi(kk,1,i+1,j) 

        grad(kk,2,i,j)  = psi(kk,2,i+1,j)

        grad(kk,3,i,j)  = psi(kk,3,i+1,j)

    END DO

   END IF

END DO
END DO

END FUNCTION grad

1 个答案:

答案 0 :(得分:4)

如果您正在寻找简洁,我想您会比您简明得多。您提供的整个功能可以像这样重写:

Microsoft.ServiceFabric

正如@IanBush所说,分配默认值然后修改特殊情况似乎是一个很好的方法。此外,array sections notation是Fortran语言独特而强大的功能之一,可用于提高表达能力而又不影响清晰度。

纯冒号表示此维度中的所有值,而值之间的冒号表示仅此维度中此范围内的值

所以,当我写function grad(psi) implicit none integer, parameter :: nx = 24, ny = 24, nxx = nx / 2, nyy = ny / 2 real, parameter :: pi = 4 * atan(1.0), f0 = pi ** 2 * 1.3 complex, dimension(3,3,-nx:nx,-ny:ny) :: psi, grad grad(:,:,-nx+1:nx-1,-ny+1:ny-1) = psi(:,:,-nx+2:nx,-ny+1:ny-1) grad(:,:,0,0) = psi(:,:,1,0) grad(:,:,[-nxx,nxx],[-nyy,nyy,ny]) = psi(:,:,[-nxx+1,nxx+1],[-nyy,nyy,ny]) - f0 * psi(:,:,[-nxx,nxx],[-nyy,nyy,ny]) !grad(:,:,nx,[-nyy,nyy]) = psi(:,:,nx+1,[-nyy,nyy]) - f0 * psi(:,:,nx,[-nyy,nyy]) end 时,我的意思是:我是将数组grad(:,:,-nx+1:nx-1,-ny+1:ny-1) = psi(:,:,-nx+2:nx,-ny+1:ny-1)中的值分配给psi;我包括了第一个维度中的所有值,但仅包括了两个最后维度中的一个子集(我不包括第一个维度和最后一个维度);此外,它们直接映射到第三个维度以外的地方,后者映射到grad 中的等效位置的下一个位置。

当我写psi时,我指定的是索引列表,而不是第三维的索引范围。这将包括两个列表的总组合:grad(:,:,[-nxx,nxx],[-nyy,nyy,ny])-nxx,-nyy-nxx,nyy-nxx,ny ...

此表示法的一个优点是,由于它更明显且更接近数学表示法,因此更容易发现不一致之处。这就是为什么最后一行被注释掉的原因:索引nxx,-nyy超出了您编写的代码的第8个和第9个条件的范围。我不知道您提供的示例代码是否为官方代码;如果是这样,则应该更正您的算法(并且,由于您仅从倒数第二个索引循环到倒数第二个索引,因此您实际上永远不会触及这些条件...)。

作为其他建议,您可以将自定义函数放在模块中,这样就可以将所有这些参数声明传递给模块范围。此外,您可以考虑假定形状的数组参数。