问题描述
我在我正在使用的旧代码中遇到了嵌套的 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 questionson this site (and external resources), this is mybest 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 itwith two end do
statements, and this is further complicated by the go to
. My rewrite requiredduplicating 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 theoriginal
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 循环的非阻塞形式令人困惑且难以维护.共享终止和标记操作语句的双重使用以及终止和分支目标特别容易出错.
如果我们有一个共享终止的非阻塞 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.
如果我们从最里面的结构分支到动作语句(使用go to
),比如
If we branch to the action statement (with go to
) from the innermost 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).
如果分支不在最里面的构造中,情况肯定会更复杂.为了清楚这个答案,我不会在这里讨论这种情况.
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 共享的操作语句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!