熟悉了C语言和Python中的行优先模式,上手Fortran的列优先模式时候有点绕,大致在这整理下思路。
无论对于C或者Fortran数据对象在内存中都是连续排列的。比如我初始化一个3×3的二维数组.
C语言

1
2
3
4
5
int c[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};

Fortran

1
2
3
integer :: f(3, 3)
integer :: r, c
data ((m(r, c), r=1, 3), c=1, 3) /(i, i=1,9)/ ! 注意我这里是按照列进行初始化的

通过上面两种语言的初始化数组的方式,数据对象在内存中存放的方式都是
1|2|3|4|5|6|7|8|9
但是C和fortran对连续内存块进行随机存取时候的索引优先是不同的,C是按照行优先,也就是stride等于1,上述数据对象的分别为:

1
c[0][0], c[0][1], c[0][2], c[1][0], c[1][1], c[1][2], c[2][0], c[2][1], c[2][2]

Fortran是列优先, stride等于3,上述对象分别为:
1
f(1, 1), f(2, 1), f(3, 1), f(1, 2), f(2, 2), f(3, 2), f(1, 3), f(2, 3), f(3, 3)

对于经常使用的话,我觉得直接按照线性代数里面最直观的列向量来处理就行,估计Fortran在设计的时候也是科学家们方便操作列向量才这么设计的。

Fortran数组输出时的注意,
write(*, *) f进行输出时,是直接按照内存顺序输出的,也就是一列一列输出,但是看起来是一行一行的。
例如,

1
2
3
4
5
6
7
8
9
10
11
12
13
program ex0714
implicit none
integer :: i, j
integer, parameter :: size = 5
integer :: m(size, size)

forall(i = 1:size, j = 1:size, i < j) m(i, j) = 1
forall(i = 1:size, j = 1:size, i == j) m(i, j) = 2
forall(i = 1:size, j = 1:size, i > j) m(i, j) = 3

write(*, "(5(5I5, /))") m
stop
end program ex0714

输出就为

1
2
3
4
5
2    3    3    3    3
1 2 3 3 3
1 1 2 3 3
1 1 1 2 3
1 1 1 1 2

和我本意不同,所以要按照我的顺序输出就应该改一下输出顺序

1
write(*, "(5(5I5, /))") ((m(i, j), j=1, size), i=1, size)

输出:

1
2
3
4
5
2    1    1    1    1
3 2 1 1 1
3 3 2 1 1
3 3 3 2 1
3 3 3 3 2

以上

Comments