【问题标题】:Restart a loop in Fortran在 Fortran 中重新启动循环
【发布时间】:2017-02-03 14:36:52
【问题描述】:

我有一个看起来像这样的算法:

10 WRITE (*,*) "Start"
DO I = 1, 10
WRITE (*,*) "Step"
IF(I .EQ. 5) then 
    go to 10
END IF
END DO

我想在 if 语句执行时重新启动循环。但是,我不想使用 go to,我尝试了这个:

10 WRITE (*,*) "Start"
DO I = 1, 10
WRITE (*,*) "Step"
IF(I .EQ. 5) then 
    I = 0; CYCLE
END IF
END DO

但是我得到了一个错误,即我无法在循环内重新定义 I 变量。所以我不确定如何解决这个问题。任何帮助将不胜感激

【问题讨论】:

  • 看来你正在努力学习,这很好。您接受的答案不是解决问题的最佳方法。

标签: algorithm loops fortran fortran90 fortran77


【解决方案1】:

表达这个问题的一个概念上简单的方法是:“我想重复一个循环直到它完成,那里有一些中止条件”。

这个“重复直到完成”习惯上是一个带有不确定迭代的 do 构造:

do
  ...  ! Our actions; we exit this outer loop when we are satisfied
end do

[这也可以表述为一个 do-while 循环。]

内循环:

do
  do i=1,10
     ... ! A conditional statement which aborts the inner loop
     ... ! And some actions
  end do
  ! And once we're complete we exit the outer loop
end do

现在只需处理“中止内部”和“退出外部”。这里cycleexit

outer: do
  print*, 'Start'
  do i=1,10
    print*, 'Step'
    if (...) cycle outer   ! Abort the inner loop
  end do
  exit outer  ! The inner loop completed, so we're done
end do outer

标记外循环,以便内循环中的cycle 语句可以引用它。如果没有该标签,cycle 将循环包含它的最内层循环。

【讨论】:

    【解决方案2】:

    这里的某个地方可能有一个错字,但这在“do while”的意义上还有一些其他的想法。

    即人们可以对进来的东西进行投票。

    ... USE ISO... etc stuff.
    REAL(KIND=C_FLOAT), DIMENSION(10) :: A
    LOGICAL(KIND=C_BOOL)              :: Question1 = .TRUE.
    LOGICAL(KIND=C_BOOL)              :: Question2 = .TRUE.
    INTEGER(KIND=C_INT)               :: Index     = 0
    INTEGER(KIND=C_INT)               :: I         = 5
    
    WRITE(*,*)'Enter first index to skip:"
    READ(*,*) I
    
    Outer_Loop: DO WHILE (Question1)    ! .eq. .TRUE.
    
      Inner_Loop:  DO WHILE (Question2) ! .EQV. .TRUE.
        Index = Index + 1
        IF(Index > UBOUND(A,1)) THEN
          Question1 = .FALSE.
          Question2 = .FALSE.
          Exit
        ENDIF
        IF(Index == I) EXIT
    
        !Whatever like  A(INdex) = something....
    
      ENDDO Inner_Loop
    
      IF(Question1) THEN   !We must have more to possibly read or do...
        WRITE(*,*)'Do more? 1=yes, 0=No"
        READ(*,*) I
        IF(I == 1) THEN
          WRITE(*,*)'Enter next index to skip:"
          READ(*,*) I
          Question2 = .TRUE.
      !and one can do a reset of I=0 here, which then becomes I=1 the next time through the inner loop...
        ELSE
          Question1 = .FALSE.
          Question2 = .FALSE.
          EXIT
        ENDIF
      ELSE   !Must have gotten here to exit at the end of array?
        EXIT
      ENDIF
    ENDDO Outer_Loop
    

    【讨论】:

      【解决方案3】:

      我可以建议解决此问题的方法:使用 while 循环或递归函数(很大程度上取决于您的实际算法)。我附上了这两种情况的示例代码(请记住,使用保存限定符的变量不是最好的主意,最好通过将变量作为参数传递给函数来做到这一点 - 这里只是为了简单起见)

      module functions
      
          implicit none
      
          integer :: restarted, save = 0
      contains
      
          recursive subroutine restart_loop
              integer :: i
      
              do i = 1, 10
                  print*, i
                  if ( i == 5 .and. restarted < 5 ) then
                      restarted = restarted + 1
                      call restart_loop
                      exit
                  end if            
              end do        
          end subroutine restart_loop
      
          subroutine while_loop
              integer :: i = 1
      
              do while (i <= 10)
                  print*, i
                  if ( i == 5 .and. restarted < 5 ) then
                      i = 1
                      restarted = restarted + 1
                  end if
                  i = i + 1
              end do
          end subroutine while_loop
      end module functions
      
      program test_prog
          use functions
      
          implicit none
      
          call while_loop
      end program test_prog
      

      【讨论】:

      • 如何在主程序中放置子程序?当我这样做时,我总是会出错((1)处的不可分类声明)。子程序仅在它们位于主程序之外或在结束语句之前对我有用:/
      • @efefef 你没有,这在 Fortran 中是不可能的。正如您在此处看到的,我正在定义一个包含子例程的模块 - 我认为这比仅定义子例程更好,因为它提供了某些(有限的)命名空间功能。注意“使用功能”这一行 - 这是您导入模块以供使用的方式。
      • @efefef 我强烈建议您在这里查看一些 fortran documentation。将子程序放在模块中是一个非常的好主意。另请参阅this doc page,了解如何在程序单元中包含子例程。
      • 知道如何将这样的变量传递给子程序吗?字符::P(12,12) 我试过这个调用sub(P),和subroutine subroutine sub(P),但是不行。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-04
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多