现代 Fortran 等效于嵌套 DO 和 GO TO 共享的动作语句
Modern Fortran equivalent of an action statement shared by nested DO and GO TO
我在使用的旧代码中发现了一个嵌套的 do
结构,希望能够理解并实现现代化。它使用相同的标记动作语句来终止 do
循环,以及 go to
语句。这是一个简化版本,它通过一些其他微不足道的操作说明了原始代码的逻辑:
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
看了其他questions
on this site(和外部资源),这是我的
尽最大努力重写原始代码的逻辑,没有过时的功能(和 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
我用以下程序测试了代码,包括 triggering/not 触发 go to
语句的替代方案:
write(*, '(a)') 'original:'
call original(2)
call original(5)
write(*, '(/,a)') 'modern:'
call modern(2)
call modern(5)
end
它为原始和我的现代重写提供了相同的结果:
original:
6
48
modern:
6
48
重写 do
循环的操作语句很复杂(对我来说),不能简单地替换它
有两个 end do
语句,go to
使情况更加复杂。我需要重写
复制动作语句(在 inner
循环的末尾,在 if
的主体内
陈述)。所以我的问题是:
- 处理共享标签动作语句的canonical/recommended方法是什么?
- 我的
modern
子程序是 original
子程序的正确重写吗?
- 是否可以在不复制操作语句 (
k=k+1
) 的情况下重写 original
代码?
您的 original
子例程肯定是 Fortran 标准在删除非块 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 看起来像
do 1
do 1
1 <action>
那么我们可以写出等价的
do 2
do 1
<action>
1 end do
2 end do
(这里的标签可以去掉)
动作语句只需要写一次,而且是在最内层的循环中。因为它是一个共享终止,执行它一次标志着每个 DO 构造共享它的迭代结束。
如果我们从最里面的1构造分支到动作语句(go to
),比如
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
分支的策略可用。
让我们将其应用于原始循环(忽略任何逻辑更改以获得相同效果并使用冗余语句标签)
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
,我们有(至少这些)两个简单的方法。
否定 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
并且循环会改变循环的行为(共享终止不会在循环时执行,而是在执行时执行)。
1 如果分支不在最内层结构中,情况肯定会更复杂。为了这个答案的清楚,我不会在这里解决这个问题。
我在使用的旧代码中发现了一个嵌套的 do
结构,希望能够理解并实现现代化。它使用相同的标记动作语句来终止 do
循环,以及 go to
语句。这是一个简化版本,它通过一些其他微不足道的操作说明了原始代码的逻辑:
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
看了其他questions
on this site(和外部资源),这是我的
尽最大努力重写原始代码的逻辑,没有过时的功能(和 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
我用以下程序测试了代码,包括 triggering/not 触发 go to
语句的替代方案:
write(*, '(a)') 'original:'
call original(2)
call original(5)
write(*, '(/,a)') 'modern:'
call modern(2)
call modern(5)
end
它为原始和我的现代重写提供了相同的结果:
original:
6
48
modern:
6
48
重写 do
循环的操作语句很复杂(对我来说),不能简单地替换它
有两个 end do
语句,go to
使情况更加复杂。我需要重写
复制动作语句(在 inner
循环的末尾,在 if
的主体内
陈述)。所以我的问题是:
- 处理共享标签动作语句的canonical/recommended方法是什么?
- 我的
modern
子程序是original
子程序的正确重写吗? - 是否可以在不复制操作语句 (
k=k+1
) 的情况下重写original
代码?
您的 original
子例程肯定是 Fortran 标准在删除非块 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 看起来像
do 1
do 1
1 <action>
那么我们可以写出等价的
do 2
do 1
<action>
1 end do
2 end do
(这里的标签可以去掉)
动作语句只需要写一次,而且是在最内层的循环中。因为它是一个共享终止,执行它一次标志着每个 DO 构造共享它的迭代结束。
如果我们从最里面的1构造分支到动作语句(go to
),比如
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
分支的策略可用。
让我们将其应用于原始循环(忽略任何逻辑更改以获得相同效果并使用冗余语句标签)
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
,我们有(至少这些)两个简单的方法。
否定 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
并且循环会改变循环的行为(共享终止不会在循环时执行,而是在执行时执行)。
1 如果分支不在最内层结构中,情况肯定会更复杂。为了这个答案的清楚,我不会在这里解决这个问题。