【问题标题】:How can I declare a local 'matrix' inside a subroutine in FORTRAN?如何在 FORTRAN 的子例程中声明本地“矩阵”?
【发布时间】:2013-02-15 11:10:18
【问题描述】:

我正在编写一个对矩阵求逆的子程序。 输入是矩阵 A(n x n),输出是矩阵 invA。在子例程中,我想声明一个临时矩阵“temp”维度(n x 2n),但声明引起了奇怪的问题。在这一行之后(我在下面强调),我还声明整数 i 和 j 并将它们初始化 i = 0,j = 0。 但是调试这些 i 和 j 的值,它显示 i = 1572472 !奇怪的!!!!!如果我删除代码行“real, dimension (m, m * 2) :: temp”,那么一切都很好。谁能给我解释一下为什么?

提前致谢。 (我是 .Net 中的一名优秀程序员,现在正在学习 Fortran - 但它让我发疯!)

program weird

implicit none

Real, Dimension (2,2)::B
Real, Dimension (2,2) ::B_inversed


B(1,1) = 0.6
B(1,2) = 0.8  
B(2,1) = -0.8
B(2,2) = 0.6

Call InverseMatrix(B,B_inversed)

contains

subroutine InverseMatrix(A, invA)
implicit none
real, intent(in), dimension (:,:) :: A  
real, intent(out), dimension (size(a,1),size(a,2)) :: invA 

real, dimension (size(a,1),2*size(a,2)) :: temp  <------THIS LINE CAUSES PROBLEMS


integer:: i,j
i = 0 !<------- 
j = 0 !<-------DEBUG line stops here, showing i = 3734648 !VERY WEIRD!!!!!

invA(1,1) =0.0
invA(1,2) =0.0
invA(2,1) =0.0
invA(2,2) =0.0

end subroutine

end program

这是一个非常直接的 FORTRAN 代码,但为什么我没有得到正确的 'i' 值?

【问题讨论】:

  • m 有多大?您使用什么编译器选项?这可能是由堆栈溢出引起的。
  • 嗨弗拉基米尔,我只用 4 x 4 矩阵进行了测试,问题已经发生。我正在使用英特尔 Fortran 编译器
  • 在您的子例程中,ij 实际上从未用于任何事情。你确定编译器没有优化它们——为了调试器只留下未初始化的符号(因为你用-g编译)?
  • @mgilson :我在后面的语句中使用它们..但是当我发现它们没有正确分配时,在我消除了问题的其他原因之后,我发现导致问题的行是我在上面展示了......所以不,不是编译器优化了这些变量。
  • 如果使用 write 语句而不是使用调试器输出 i 和 j 的值会发生什么?我在 Mac 上使用 gfortran 完成此操作,程序运行良好。

标签: fortran


【解决方案1】:

由于 Fortran 数组携带有关其自身大小的信息,一个更好的方法是让您开始您的子例程更像这样:

subroutine inversematrix(a, inva)
    ! ALWAYS include the next line within any scoping unit
    implicit none
    real, intent(in), dimension (:,:) :: a  ! no need to tell the compilers what the dims are
    real, intent(out), dimension (size(a,1),size(a,2)) :: inva 

    real, dimension (size(a,1),2*size(a,2)) :: temp  

要回答您的问题,我无法立即看出为什么您的代码不起作用以及为什么变量 i 没有保留您分配给它的值。不知是否与子程序的接口相连。在现代 Fortran 中,在技术上可行的情况下,确保编译器生成必要的例程接口总是一个好主意。实现这一点的一种方法是将所有例程放入模块中并使用关联它们,另一种方法是使用基本结构编写代码

program
! declarations
! executable statements
contains

subroutine ...
end subroutine

end program

而不是

subroutine ...
end subroutine

program
! declarations
! executable statements
end program

但我真的只是猜测。

使用implicit none并确保编译器生成例程接口;这些可能无法解决您眼前的问题,但它们是很好的一般指导方针,将来会为您省去很多痛苦。

【讨论】:

  • @Mark:谢谢你的新方法,它比我的要好得多。但是最后一行仍然是问题。如果我然后声明 integer::i,j 并分配 i = 0,调试器发现 i 不是 0 而是一个随机数 1767672!!!。我就是不明白这里出了什么问题!
  • 启用运行时错误检查,可能会有一些索引溢出,或者类似的问题。你可以试试-g -check all -traceback -warn all -fstack-protector -debug
  • @Mark:您的指南对编程非常有用——谢谢。下面是我的整个程序。非常直截了当-我就是不明白为什么。但是在 i = 0 之后。看来 i = 3734648。你有什么想法吗?
【解决方案2】:

英特尔编译器在优化过程中做了一些可能会影响调试器输出的事情:

  1. 它重新排列语句的顺序,因此分配 j = 0 的行可能会在分配 i = 0 的行之前运行。

  2. 它“优化”变量,不仅通过删除未使用的变量,而且通过将变量与未同时使用的其他变量组合在一起。

这两种情况似乎都无法预测(至少对我而言)。因此,如果您已修复程序以使其具有正确的行为,并且打印该值会产生正确的答案,那么调试器可能仍会显示错误的值。您可以尝试关闭/关闭优化,看看会发生什么。

【讨论】:

    猜你喜欢
    • 2014-10-11
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 2016-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多