更新:这是一个纯粹的 Fortran问题; I put the maths stuff on M.SE
考虑P
x P
对称和正定矩阵A
(P = 70000,即A
大约40 GB,使用8字节双精度)。我们想要计算逆矩阵inv(A)[1,1]
,inv(A)[2,2]
和inv(A)[3,3]
的前三个对角线元素。
我找到了James R. Bunch的this paper,他似乎在没有计算完全反inv(A)
的情况下解决了这个问题。 不幸的是他使用了Fortran和LINPACK,两者都是我从未使用过的。
我正在尝试理解这个功能:
SUBROUTINE SOLVEJ(A,LDA,P,Y,J)
INTEGER LDA,P,J
REAL A(LDA,1),Y(1)
C
INTEGER K
Y(J) = 1/A(J,J)
DO 10 K = J + 1,P
Y(K) = - SDOT(K - J,A(J,K),1,Y(J),1)/A(K,K)
10 CONTINUE
RETURN
END
其中A
是大小为LDA x P的矩阵,Y
是长度为P的向量。
你能解释为什么他在函数头中定义Y(1)
然后分配给Y(J)
? Fortran不关心定义数组的大小并让你访问超出其结束?为什么不定义Y(P)
,这似乎可以根据this Fortran Primer?
答案 0 :(得分:3)
首先,您应该了解不同的Fortran版本,尤其是77 VS 90/95及更高版本,而且确实您可以(通常)超出界限,就像在C. fortran中的数组可能会导致很多混乱,我会说这有点乱。为了将讨论局限于您的具体情况,我们可以使用这是关于虚拟数组的事实,这是一个出现在过程的伪参数列表中的数组。对于虚拟数组,我们可以有3种类型:
使事情变得复杂,(3)可以与(1)组合,并且(2)通常与延迟形状的数组分组,例如,可分配的数组。延迟形状和假定形状仅适用于Fortran 90/95及更高版本,如果您想将它们用作伪参数,则需要显式接口,因此它通常用于模块中。
所以,在你的情况下,虽然Y(1)
可以工作,因为你可以超出范围,但是非常糟糕,因为当你用-fcheck=bounds
编译程序时程序会失败。应该编写有效的Fortran 77:
REAL A(LDA,*),Y(*)
或更好:
REAL A(LDA,P),Y(P)