现代 Fortran 等效于嵌套 DO 和 GO TO 共享的操作语句 [英] Modern Fortran equivalent of an action statement shared by nested DO and GO TO

查看:11
本文介绍了现代 Fortran 等效于嵌套 DO 和 GO TO 共享的操作语句的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我正在使用的旧代码中遇到了嵌套的 do 构造,并希望能够理解和现代化.它使用相同的标记操作语句来终止 do 循环,以及 go to 语句.这是一个简化的版本,它通过一些其他琐碎的操作来说明原始代码的逻辑:

I have come across a nested do construct in an old code that I am using, and hoping to understand and modernize. It uses the same labelled action statement for termination of the do loops, as well as go to statement. Here is a simplified version, that illustrates the logic of the original code with some otherwise trivial operations:

      subroutine original(lim)
      k=0
      do 10 i=1,4
        do 10 j=1,3
          k=k-2
          if (i>lim) go to 10
          k=k+i*j
 10   k=k+1
      write(*,*) k
      return
      end

查看其他问题在这个网站上(和外部资源),这是我的尽最大努力重写原始代码的逻辑,没有过时的功能(和 go to):

After looking at other questions on this site (and external resources), this is my best effort at rewriting the logic of the original code, without obsolescent features (and go to):

subroutine modern(lim)
  integer, intent(in) :: lim
  integer :: i, j, k
  k=0
  outer: do i=1,4
    inner: do j=1,3
      k=k-2
      if (i>lim) then
        k=k+1
        cycle inner
      end if
      k=k+i*j
      k=k+1
    end do inner
  end do outer
  write(*,*) k
end subroutine modern

我使用以下程序测试了代码,包括触发/不触发 go to 语句的替代方案:

I tested the codes with the following program, including alternatives for triggering/not triggering the go to statement:

  write(*, '(a)') 'original:'
  call original(2)
  call original(5)

  write(*, '(/,a)') 'modern:'
  call modern(2)
  call modern(5)
end

它对原始版本和我的现代重写给出了相同的结果:

and it gives the same result for the original and my modern rewrite:

original:
 6
 48

modern:
 6
 48

动作语句很复杂(对我来说)重写 do 循环,不能简单地替换它有两个 end do 语句,而 go to 使这更加复杂.我需要重写复制动作语句(在 inner 循环的末尾,以及在 if 的主体内陈述).所以我的问题是:

The action statement complicated (for me) rewriting the do loops, one can not simply replace it with two end do statements, and this is further complicated by the go to. My rewrite required duplicating the action statement (at the end of the inner loop, and within the body of the if statement). So my question is this:

  • 处理共享标记操作语句的规范/推荐方式是什么?
  • 我的 modern 子程序是对 original 子程序的正确重写吗?
  • 是否可以在不复制动作语句的情况下重写原始代码(k=k+1)?
  • What is the canonical/recommended way for handling the shared labelled action statement?
  • Is my modern subroutine a correct rewrite of the original one?
  • Is it possible to rewrite the original code without duplicating the action statement (k=k+1)?

推荐答案

您的 original 子例程肯定是 Fortran 标准在删除非块 DO 构造时所考虑的代码类型:

Your original subroutine is surely the type of code that the Fortran standard had in mind when deleting non-block DO constructs:

DO 循环的非阻塞形式令人困惑且难以维护.共享终止和标记操作语句的双重使用以及终止和分支目标特别容易出错.

The nonblock forms of the DO loop were confusing and hard to maintain. Shared termination and dual use of labeled action statements as do termination and branch targets were especially error-prone.

如果我们有一个共享终止的非阻塞 DO,看起来像

If we have a non-block DO with shared termination looking like

do 1
  do 1
1 <action>

那么我们可以写出等价的

then we can write the equivalent

do 2
  do 1
    <action>
  1 end do
2 end do

(这里的标签可以去掉)

(where the labels here can be removed)

action 语句只需要编写一次,并且在最里面的循环内.因为它是一个共享终止,执行它一次标志着每个共享它的 DO 构造的迭代结束.

The action statement needs writing only once, and that's inside the innermost loop. Because it's a shared termination executing it once signals the end of the iteration of every DO construct sharing it.

如果我们从最里面的1结构分支到动作语句(使用go to),比如

If we branch to the action statement (with go to) from the innermost1 construct, like

do 1
  do 1
    go to 1
1 <action>

我们有等价的

do 3
  do 2
    go to 1
    1 <action>
  2 end do
3 end do

我们常用的替换 go to 分支的策略是可用的.

Our usual strategies for replacing go to branching then are available.

让我们将它应用到原始循环(忽略任何逻辑更改以获得相同效果并使用冗余语句标签)

Let's apply this to the original loop (ignoring any logic changes for the same effect and using redundant statement labels)

do 10 i=1,4
  do 10 j=1,3
    k=k-2
    if (i>lim) go to 10
    k=k+i*j
10 k=k+1

我们可以这样写

do 30 i=1,4
  do 20 j=1,3
    k=k-2
    if (i>lim) go to 10
    k=k+i*j
    10 k=k+1
  20 end do
30 end do

来到go to,我们有(至少有这些)两种简单的方法.

Coming to the go to, we have (at least these) two simple approaches.

否定 IF:

    if (i<=lim) k=k+i*j
    10 k=k+1

使用块:

    nogoto: block
      if (i>lim) exit nogoto
      k=k+i*j
    end block nogoto
    10 k=k+1


如您所见,行动声明的重复";来自 cycle 语句的使用.在重写的循环中,您必须复制操作语句,因为您没有到达操作语句所在的循环末尾.原始循环没有 cycle 并且循环会改变循环的行为(共享终止在循环时不执行,而是在 go-to 时执行).


As you can see, the "duplication of the action statement" comes from the use of the cycle statement. In the rewritten loops you've had to duplicate the action statement because you don't reach the end of the loop where the action statement lives. The original loop doesn't have a cycle and cycling changes the behaviour of the loop (the shared termination isn't executed when cycling but is when gone-to).

1 如果分支不在最里面的构造中,情况肯定会更复杂.为了清楚这个答案,我不会在这里讨论这种情况.

1 The situation is decidedly more complicated if the branch is not inside the innermost construct. For clarity of this answer I won't address that case here.

这篇关于现代 Fortran 等效于嵌套 DO 和 GO TO 共享的操作语句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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