我的一个非常旧的 Fortran IV (ff66) 程序存在语义问题。这引出了两个问题。 *** 背景 ***
程序应在 O(1) 内存中计算阿克曼函数。它来自这里: 旧纸
这是Henry_Gordon_Rice写的一篇论文(Gordon Rice,wiki页面规定上述论文是他写的)。为什么要读这么老的报纸?为了好玩和作为科学测试。
这里是代码:
1 INTEGER FUNCTION ACKER(M,N)
C Size of VALUE and PLACE tables is one more than LARGEST M EXPECTED (else too long computation)
2 INTEGER VALUE(6), PLACE(6)
C Test ofr Zero M
3 IF (M .NE. O) GO TO 6
4 ACKER = N+l
5 RETURN
C Non Zero M INITIALIZE FOR ITERATION
6 VALUE = 1
7 PLACE = 0
C ITERATION LOOP. GET NEW VALUE.
8 VALUE = VALUE + 1
9 PLACE = PLACE + 1
10 DO 18 I=1,M
11 IF (PLACE(I) .NE. 1) GO TO 16
C INITIATE NEW LEVEL
12 VALUE(I+1) = VALUE
13 PLACE(I+1) = 0
14 IF (I .EQ. M) GO TO 18
15 GO TO 8
16 IF (PLACE(I) .NE. VALUE(I+1) GO TO 8
17 VALUE(I+1) = VALUE
18 PLACE(I+1)=PLACE(I+1)+1
C CHECK FOR END OF ITERATION
19 IF (PLACE(M+1) .NE. N) GO TO 8
20 ACKER = VALUE
21 RETURN
22 END
并且没有评论。
1 INTEGER FUNCTION ACKER(M,N)
2 INTEGER VALUE(6), PLACE(6)
3 IF (M .NE. O) GO TO 6
4 ACKER = N+l
5 RETURN
6 VALUE = 1
7 PLACE = 0
8 VALUE = VALUE + 1
9 PLACE = PLACE + 1
10 DO 18 I=1,M
11 IF (PLACE(I) .NE. 1) GO TO 16
12 VALUE(I+1) = VALUE
13 PLACE(I+1) = 0
14 IF (I .EQ. M) GO TO 18
15 GO TO 8
16 IF (PLACE(I) .NE. VALUE(I+1) GO TO 8
17 VALUE(I+1) = VALUE
18 PLACE(I+1)=PLACE(I+1)+1
19 IF (PLACE(M+1) .NE. N) GO TO 8
20 ACKER = VALUE
21 RETURN
22 END
与大多数迭代程序相比,这是一个非常短的程序:
*** 问题***
因此,在阅读代码、了解其工作原理时,有两件事困扰了我:
(1) 如果 PLACE 是一个数组/表,那么赋值 PLACE=1 是如何工作的? 1 无处不在? 1 到第一个单元格? PLACE也是一种隐藏索引?
这是关于 PLACE = PLACE + 1 的相同问题。它是如何工作的? (记住 PLACE 不是整数变量而是数组)
(2) DO-LOOP(一种 for 循环)内的一些 GOTO 脱离了 do 循环的范围(主体)。然后代码可以重新进入 do 循环的范围/主体。如果是,变量 J 是否重置?或者是否使用了副本(所以会有一个隐藏的堆栈?)。
提前致谢, 弗雷德里克·加瓦
ps : 有关 Fortran IV 版本的一些参考资料 手册
我尝试将代码转换为 Java,但如果不理解语义,我就做不到。我尝试用“g77 -ff66”编译它,但没有成功。我尝试阅读有关 Fortran IV 和阿克曼函数迭代算法的论文
(我绝对不是 Fortran 程序员...)
第 1 部分)
一次分配或使用整个数组是所谓的“数组语法”,仅在 Fortran 90 中引入。据我所知,像
PLACE = 0
这样的东西在 Fortran 66 或 77 中是非法的。所以这里有两个假设:
PLACE
(可能)是 PLACE(1)
但后一种假设不太可能,因为代码还包含类似
VALUE(I+1) = VALUE
的内容,即将整个数组分配给标量元素:这在所有 Fortran 标准中都是非法的,无论是旧的还是新的。
第 2 部分)
使用 goto 语句逃离 do 循环是可以的(在 Fortran 90 之前这是唯一的方法)。在您的示例中,当再次进入 do 循环时,
J
变量只是重置为循环的初始值,并且该变量没有新实例。
授权/未授权的是使用 goto 语句在 do 循环内跳转。
我认为这是代码的正确版本。
GO TO 18
替换为 GO TO 19
1 INTEGER FUNCTION ACKER(M,N)
2 INTEGER VALUE(6), PLACE(6)
3 IF (M .NE. O) GO TO 6
4 ACKER = N+l
5 RETURN
6 VALUE(1) = 1
7 PLACE(1) = 0
8 VALUE(1) = VALUE(1) + 1
9 PLACE(1) = PLACE(1) + 1
10 DO 18 I=1,M
11 IF (PLACE(I) .NE. 1) GO TO 16
12 VALUE(I+1) = VALUE(1)
13 PLACE(I+1) = 0
14 IF (I .EQ. M) GO TO 19
15 GO TO 8
16 IF (PLACE(I) .NE. VALUE(I+1)) GO TO 8
17 VALUE(I+1) = VALUE(1)
18 PLACE(I+1)=PLACE(I+1)+1
19 IF (PLACE(M+1) .NE. N) GO TO 8
20 ACKER = VALUE(1)
21 RETURN
22 END