通过重新构造if语句/do循环来避免重复代码 [英] avoid duplicating code by re-structuring if statement/do loop

查看:128
本文介绍了通过重新构造if语句/do循环来避免重复代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Hi I am trying to impose a specific condition on my function at many different spatial points in my grid. However I am duplicating lots of code and it's becoming increasingly inefficient.

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

How can I do what I need to by simply using a do loop? The specific condition I am trying to impose on my function is the same at all the different spatial points so I figure theres a way to do all of this in a single loop. Or how can I combine all these If/else if statements into a single statement? There must be a more efficient way than what I am doing.

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

I provided a sample code below.

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

推荐答案

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

If you are looking for conciseness, I'd say you can be much, much more concise than you are. The whole function you provided can be rewritten just like this:

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

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

As said by @IanBush, assigning the default values then modifying the special cases seems a good aproach. Also, array sections notation is one of the distinctive and powerful features of Fortran language, and can be used to increase expressiveness without compromising clarity.

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

Pure colons mean all values in this dimension, and a colon between values means only values within this range in this dimension.

所以,当我写grad(:,:,-nx+1:nx-1,-ny+1:ny-1) = psi(:,:,-nx+2:nx,-ny+1:ny-1)时,我的意思是:我正在将数组psi中的值分配给grad;我包括了第一个维度中的所有值,但仅包括了两个最后维度中的一个子集(我不包括第一个维度和最后一个维度);此外,它们直接映射到第三个维度以外的地方,后者映射到psi 中的等效位置的下一个位置.

So, when I write grad(:,:,-nx+1:nx-1,-ny+1:ny-1) = psi(:,:,-nx+2:nx,-ny+1:ny-1) I mean: i'm assigning values from the array psi to grad; I include all values from the two first dimensions, but only a subset of the two last dimensions (I'm excluding the fisrt and last in each); also, they are mapped directly except for the third dimension, that maps to the next of the equivalent position in psi.

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

When I write grad(:,:,[-nxx,nxx],[-nyy,nyy,ny]), I am specifying a list of indices instead of a range for the third and fourth dimensions. This will include the total combinations of the two lists: -nxx,-nyy, -nxx,nyy, -nxx,ny, nxx,-nyy...

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

One advantage of this notation is that, as it is more obvious and closer to the mathematical notation, it is easier to catch inconsistencies. That is why the last line is commented out: an index nx+1, as you would have in the 8th and 9th conditions in the code you wrote, would be out of bounds. I don't know if the sample code you presented is official; if it is, you should correct your algorithm (well, as you are looping only from the second to the second-last indices, you'd actually never touch those conditions...).

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

As an additional advice, you could put your custom functions in a module, so you could pass all those parameter declarations to the module scope. Moreover, you could then consider assumed-shape array arguments.

这篇关于通过重新构造if语句/do循环来避免重复代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆