矩阵初始化 - 如何避免重叠?
Matrix initialization - how to avoid overlapping?
我有一个 21x21 矩阵,其中大部分都包含 1。某些元素需要用离散数来初始化。现有解决方案是两步初始化:首先将所有元素设置为 1,然后将所选元素重新分配给离散数字。
这是在遗留的 FORTRAN77 代码中实现的,见下文,并且它与 gfortran-4.9 编译得很好(即使没有警告)。
但是,我需要在较旧的服务器上编译它 运行 gfortran-4.4。由于 "overlapping initialization",这与 f2c 或 g95 编译器等替代工具一起失败了。
现在,我如何重新编码避免在特殊的 BLOCK DATA 程序单元中重叠的问题?我也认为不推荐使用英特尔 Fortran 编译器,因为无法保证初始化顺序。
SUBROUTINE TEST
REAL*8 MAT(21,21)
COMMON /PARAMETERS/ MAT
END
BLOCK DATA
REAL*8 MAT(21,21)
COMMON /PARAMETERS/ MAT
DATA MAT/441*1/
DATA (MAT(1,J),J=2,19)/
& 0.971440D0, 0.940444D0, 1, 0.994435D0, 0.708218D0,
& 0.931484D0, 1.170520D0, 0.990124D0, 1, 1.019530D0,
& 0.989844D0, 1.002350D0, 0.999248D0, 1.107274D0, 0.880880D0,
& 0.880973D0, 0.881047D0, 0.881141D0/
DATA (MAT(2,J),J=3,14)/
& 1.022740D0, 0.970120D0, 0.945939D0, 0.744954D0, 0.902271D0,
& 1.084320D0, 1.005710D0, 1.021000D0, 0.944914D0, 0.973384D0,
& 0.959340D0, 0.945520D0/
DATA (MAT(3,J),J=4,19)/
& 0.925053D0, 0.940237D0, 0.849408D0, 0.955052D0, 1.281790D0,
& 1.5D0, 1, 0.904849D0, 0.897342D0, 0.724255D0,
& 0.859744D0, 0.855134D0, 0.831229D0, 0.808310D0, 0.784323D0,
& 0.745171D0/
DATA (MAT(4,J),J=5,14)/1.022540D0, 0.493148D0, 0.944871D0,
& 1.144440D0, 3*1, 1.013040D0, 1, 1.00532D0/
DATA (MAT(5,J),J=8,12)/1.034787D0, 3*1, 1.0049D0/
DATA (MAT(7,J),J=15,19)/1.008492D0, 1.010124D0, 1.011501D0,
& 1.012821D0, 1.014089D0/
DATA (MAT(8,J),J=9,12)/1.1D0, 1, 1.3D0, 1.3D0/
END
如果不允许"overlapping initialization",一个简单的做法可能就是在具体数据前后插入n*1
,其余部分也补1,例如
BLOCK DATA
REAL*8 MAT(21,21)
COMMON /PARAMETERS/ MAT
DATA MAT(1,:) / 1,
& 0.971440D0, 0.940444D0, 1, 0.994435D0, 0.708218D0,
& 0.931484D0, 1.170520D0, 0.990124D0, 1, 1.019530D0,
& 0.989844D0, 1.002350D0, 0.999248D0, 1.107274D0, 0.880880D0,
& 0.880973D0, 0.881047D0, 0.881141D0, 2*1 /
DATA MAT(2,:) / 2*1,
& 1.022740D0, 0.970120D0, 0.945939D0, 0.744954D0, 0.902271D0,
& 1.084320D0, 1.005710D0, 1.021000D0, 0.944914D0, 0.973384D0,
& 0.959340D0, 0.945520D0, 7*1 /
DATA MAT(3,:) / 3*1,
& 0.925053D0, 0.940237D0, 0.849408D0, 0.955052D0, 1.281790D0,
& 1.5D0, 1, 0.904849D0, 0.897342D0, 0.724255D0,
& 0.859744D0, 0.855134D0, 0.831229D0, 0.808310D0, 0.784323D0,
& 0.745171D0, 2*1 /
DATA MAT(4,:) / 4*1,
& 1.022540D0, 0.493148D0, 0.944871D0,
& 1.144440D0, 3*1, 1.013040D0, 1, 1.00532D0, 7*1 /
DATA MAT(5,:) / 7*1, 1.034787D0, 3*1, 1.0049D0, 9*1 /
DATA MAT(6,:) / 21*1 /
DATA MAT(7,:) / 14*1,
& 1.008492D0, 1.010124D0, 1.011501D0,
& 1.012821D0, 1.014089D0, 2*1 /
DATA MAT(8,:) / 8*1, 1.1D0, 1, 1.3D0, 1.3D0, 9*1 /
DATA MAT(9:21,:) / 273*1 /
END
如评论中所建议,另一种方法是用数组赋值替换所有 DATA 语句,例如,
SUBROUTINE init_data
IMPLICIT NONE
REAL*8 MAT(21,21), ONE
COMMON /PARAMETERS/ MAT
PARAMETER ( ONE = 1.0D0 )
INTEGER i
MAT(:,:) = ONE
MAT(1, 2:19) = [
& 0.971440D0, 0.940444D0, ONE, 0.994435D0, 0.708218D0,
& 0.931484D0, 1.170520D0, 0.990124D0, ONE, 1.019530D0,
& 0.989844D0, 1.002350D0, 0.999248D0, 1.107274D0, 0.880880D0,
& 0.880973D0, 0.881047D0, 0.881141D0 ]
MAT(2, 3:14) = [
& 1.022740D0, 0.970120D0, 0.945939D0, 0.744954D0, 0.902271D0,
& 1.084320D0, 1.005710D0, 1.021000D0, 0.944914D0, 0.973384D0,
& 0.959340D0, 0.945520D0 ]
MAT(3, 4:19) = [
& 0.925053D0, 0.940237D0, 0.849408D0, 0.955052D0, 1.281790D0,
& 1.5D0, ONE, 0.904849D0, 0.897342D0, 0.724255D0,
& 0.859744D0, 0.855134D0, 0.831229D0, 0.808310D0, 0.784323D0,
& 0.745171D0 ]
MAT(4, 5:14) = [ 1.022540D0, 0.493148D0, 0.944871D0,
& 1.144440D0, (ONE,i=1,3), 1.013040D0, ONE, 1.00532D0 ]
MAT(5, 8:12) = [ 1.034787D0, (ONE,i=1,3), 1.0049D0 ]
MAT(7, 15:19) = [ 1.008492D0, 1.010124D0, 1.011501D0,
& 1.012821D0, 1.014089D0 ]
MAT(8, 9:12) = [ 1.1D0, ONE, 1.3D0, 1.3D0 ]
END
这对我来说似乎更整洁。虽然我已经确认此代码适用于 gfortran 4.4.7,但对于更旧的编译器,可能需要使用 (/.../)
而不是 [...]
,例如 (/ 1.0d0, 2.0d0, ... /)
。另请注意,在第二种方法中,我们需要在程序的某个点调用 init_data
,与 BLOCK DATA
相比,在 BLOCK DATA
中,数据在程序执行时自动初始化。
可以构造一个只调用一次的例程。
该例程将从准备好的文件中读取矩阵的数据。
这肯定会解决您使用任何编译器的问题。
我有一个 21x21 矩阵,其中大部分都包含 1。某些元素需要用离散数来初始化。现有解决方案是两步初始化:首先将所有元素设置为 1,然后将所选元素重新分配给离散数字。
这是在遗留的 FORTRAN77 代码中实现的,见下文,并且它与 gfortran-4.9 编译得很好(即使没有警告)。
但是,我需要在较旧的服务器上编译它 运行 gfortran-4.4。由于 "overlapping initialization",这与 f2c 或 g95 编译器等替代工具一起失败了。
现在,我如何重新编码避免在特殊的 BLOCK DATA 程序单元中重叠的问题?我也认为不推荐使用英特尔 Fortran 编译器,因为无法保证初始化顺序。
SUBROUTINE TEST
REAL*8 MAT(21,21)
COMMON /PARAMETERS/ MAT
END
BLOCK DATA
REAL*8 MAT(21,21)
COMMON /PARAMETERS/ MAT
DATA MAT/441*1/
DATA (MAT(1,J),J=2,19)/
& 0.971440D0, 0.940444D0, 1, 0.994435D0, 0.708218D0,
& 0.931484D0, 1.170520D0, 0.990124D0, 1, 1.019530D0,
& 0.989844D0, 1.002350D0, 0.999248D0, 1.107274D0, 0.880880D0,
& 0.880973D0, 0.881047D0, 0.881141D0/
DATA (MAT(2,J),J=3,14)/
& 1.022740D0, 0.970120D0, 0.945939D0, 0.744954D0, 0.902271D0,
& 1.084320D0, 1.005710D0, 1.021000D0, 0.944914D0, 0.973384D0,
& 0.959340D0, 0.945520D0/
DATA (MAT(3,J),J=4,19)/
& 0.925053D0, 0.940237D0, 0.849408D0, 0.955052D0, 1.281790D0,
& 1.5D0, 1, 0.904849D0, 0.897342D0, 0.724255D0,
& 0.859744D0, 0.855134D0, 0.831229D0, 0.808310D0, 0.784323D0,
& 0.745171D0/
DATA (MAT(4,J),J=5,14)/1.022540D0, 0.493148D0, 0.944871D0,
& 1.144440D0, 3*1, 1.013040D0, 1, 1.00532D0/
DATA (MAT(5,J),J=8,12)/1.034787D0, 3*1, 1.0049D0/
DATA (MAT(7,J),J=15,19)/1.008492D0, 1.010124D0, 1.011501D0,
& 1.012821D0, 1.014089D0/
DATA (MAT(8,J),J=9,12)/1.1D0, 1, 1.3D0, 1.3D0/
END
如果不允许"overlapping initialization",一个简单的做法可能就是在具体数据前后插入n*1
,其余部分也补1,例如
BLOCK DATA
REAL*8 MAT(21,21)
COMMON /PARAMETERS/ MAT
DATA MAT(1,:) / 1,
& 0.971440D0, 0.940444D0, 1, 0.994435D0, 0.708218D0,
& 0.931484D0, 1.170520D0, 0.990124D0, 1, 1.019530D0,
& 0.989844D0, 1.002350D0, 0.999248D0, 1.107274D0, 0.880880D0,
& 0.880973D0, 0.881047D0, 0.881141D0, 2*1 /
DATA MAT(2,:) / 2*1,
& 1.022740D0, 0.970120D0, 0.945939D0, 0.744954D0, 0.902271D0,
& 1.084320D0, 1.005710D0, 1.021000D0, 0.944914D0, 0.973384D0,
& 0.959340D0, 0.945520D0, 7*1 /
DATA MAT(3,:) / 3*1,
& 0.925053D0, 0.940237D0, 0.849408D0, 0.955052D0, 1.281790D0,
& 1.5D0, 1, 0.904849D0, 0.897342D0, 0.724255D0,
& 0.859744D0, 0.855134D0, 0.831229D0, 0.808310D0, 0.784323D0,
& 0.745171D0, 2*1 /
DATA MAT(4,:) / 4*1,
& 1.022540D0, 0.493148D0, 0.944871D0,
& 1.144440D0, 3*1, 1.013040D0, 1, 1.00532D0, 7*1 /
DATA MAT(5,:) / 7*1, 1.034787D0, 3*1, 1.0049D0, 9*1 /
DATA MAT(6,:) / 21*1 /
DATA MAT(7,:) / 14*1,
& 1.008492D0, 1.010124D0, 1.011501D0,
& 1.012821D0, 1.014089D0, 2*1 /
DATA MAT(8,:) / 8*1, 1.1D0, 1, 1.3D0, 1.3D0, 9*1 /
DATA MAT(9:21,:) / 273*1 /
END
如评论中所建议,另一种方法是用数组赋值替换所有 DATA 语句,例如,
SUBROUTINE init_data
IMPLICIT NONE
REAL*8 MAT(21,21), ONE
COMMON /PARAMETERS/ MAT
PARAMETER ( ONE = 1.0D0 )
INTEGER i
MAT(:,:) = ONE
MAT(1, 2:19) = [
& 0.971440D0, 0.940444D0, ONE, 0.994435D0, 0.708218D0,
& 0.931484D0, 1.170520D0, 0.990124D0, ONE, 1.019530D0,
& 0.989844D0, 1.002350D0, 0.999248D0, 1.107274D0, 0.880880D0,
& 0.880973D0, 0.881047D0, 0.881141D0 ]
MAT(2, 3:14) = [
& 1.022740D0, 0.970120D0, 0.945939D0, 0.744954D0, 0.902271D0,
& 1.084320D0, 1.005710D0, 1.021000D0, 0.944914D0, 0.973384D0,
& 0.959340D0, 0.945520D0 ]
MAT(3, 4:19) = [
& 0.925053D0, 0.940237D0, 0.849408D0, 0.955052D0, 1.281790D0,
& 1.5D0, ONE, 0.904849D0, 0.897342D0, 0.724255D0,
& 0.859744D0, 0.855134D0, 0.831229D0, 0.808310D0, 0.784323D0,
& 0.745171D0 ]
MAT(4, 5:14) = [ 1.022540D0, 0.493148D0, 0.944871D0,
& 1.144440D0, (ONE,i=1,3), 1.013040D0, ONE, 1.00532D0 ]
MAT(5, 8:12) = [ 1.034787D0, (ONE,i=1,3), 1.0049D0 ]
MAT(7, 15:19) = [ 1.008492D0, 1.010124D0, 1.011501D0,
& 1.012821D0, 1.014089D0 ]
MAT(8, 9:12) = [ 1.1D0, ONE, 1.3D0, 1.3D0 ]
END
这对我来说似乎更整洁。虽然我已经确认此代码适用于 gfortran 4.4.7,但对于更旧的编译器,可能需要使用 (/.../)
而不是 [...]
,例如 (/ 1.0d0, 2.0d0, ... /)
。另请注意,在第二种方法中,我们需要在程序的某个点调用 init_data
,与 BLOCK DATA
相比,在 BLOCK DATA
中,数据在程序执行时自动初始化。
可以构造一个只调用一次的例程。 该例程将从准备好的文件中读取矩阵的数据。 这肯定会解决您使用任何编译器的问题。