FORTRAN从哪里获取这些价值?

时间:2013-11-09 17:56:54

标签: fortran gfortran

我是FORTRAN的绝对初学者,正在努力将1000行FORTRAN源文件转换为MATLAB供我自己使用。到目前为止,我已经做好了大量的PRINT语句来跟踪变量并确保数学运算正常。我在FORTRAN发生了一件奇怪的事情,我无法解决这个问题。

有一个子程序,定义如此

subroutine addprc 
complex tmat,b,ci,c1,c2,cim,ab1(50),ab2(50),acans(10,2),fg1(50),fg2(50)
common dtr,rtd,pi 
common /mtxcom/ nrank,nranki,tmat(50,50),b(50,50),cmxnrm(25)
common /cmvcom/ nm,kmv,cmv,twm,prodm 

下面有一些commondimension分配,但它们不应该相关。第一次定义ab1(50)数组是在此子例程中。对于我的MATLAB脚本,我已将其初始化为ab1=zeros(1,50);。然后在此循环中使用它(在FORTRAN中):

do 20 n = 1,nrank 
np = n+nrank 
cn = real(n)
n1 = n+1 
c1 = 4.0*ci**n 
c2 = 4.0*ci**n1 
p1 = cn*costh*pnmllg(n1)-(cn+cmv)*pnmllg(n) 
p2 = cmv*pnmllg(n1) 
ab1(n-ij) = c1*p2*uu1 
ab1(np-ijt) = -c2*p1*uu1 
ab2(n-ij) = -c1*p1*uu2 
ab2(np-ijt) = c2*p2*uu2 

我已经检查了所有其他变量的值,他们同意我的MATLAB脚本。向后工作我已经解决了ab1已经包含值的问题。在循环之前的打印命令,例如

PRINT *,'before ab1', SUM(ab1)
do 20 n = 1,1

返回(107.500008, 5.38305187)。这是一个复杂的数字,所以这两个值很好,但是它不完全是它有任何东西吗?事实上,唯一一次使用ab1就是在这段代码中。

这里有什么我想念的吗?我查看了源文件(ctrl-f:ab1)以查找它的任何实例。原始源是.for文件,我使用gfortran在Eclipse下编译它们。谢谢你的时间。

2 个答案:

答案 0 :(得分:2)

ab1是小数组(50 * 8 = 400字节),因此最有可能在程序堆栈上分配。无论何时调用子例程,堆栈都用于存储局部变量以及调用者的返回地址。最初,堆栈页面包含全零,但随着子程序被调用,它会增长并填充一些数字。稍后当子例程返回时,堆栈指针被更改但值仍保留在堆栈上,稍后将被新调用覆盖。当分配ab1时,其内存最初将填充来自先前调用的子例程的旧堆栈值。大多数FORTRAN编译器默认情况下不会生成初始化堆栈变量的指令,因为它可能是一项昂贵的操作。

如果你的程序是完全确定的,即没有依赖于某些(伪)随机数值的子程序调用或者初始PRNG种子总是相同的话,那么返回堆栈的所有其他内容都没有在你的程序的许多执行之间会有所不同,例如一个在晚上,一个在早上。

这就是SUM(ab1)始终返回(107.500008, 5.38305187)的原因。它实际上是一个GoodThing(tm) - 它表明您的计算机是一个确定性设备,即它在给定相同算法和相同输入的情况下再现输出,因此可用于执行编程任务。这也是一个BadThing(tm),因为可预测的堆栈值是对OS安全性的许多攻击的基础,但这远远超出了你的问题的范围。

答案 1 :(得分:1)

只是想知道:你会期待什么呢?

这些值来自记忆。当您调用定义变量的某个内容(函数/程序/子例程)时,某些内存与定义的变量相关联,但在您为变量赋值之前,它将使用之前存在于内存中的内容。由于计算机内存在不被重置的情况下不断被重用,你可以从已经结束的另一个被调用的函数/子例程的变量获得值,来自其他进程的一块内存(除了必须由内核清空的一些页面)它们可能包含私人数据)或其他任何内容。一般规则是没有人会做如此昂贵的操作,如将内存设置为某个值,除非他致命地需要这个(例如,在这里你设置与变量相关的内存与你需要的数字或不擦除内存是一个潜在的安全漏洞)

总结:这些值来自未初始化的内存。确切的内容未定义。

在访问未初始化的内存时不会出错,因为检查内存是否已初始化是一项非常昂贵的操作。但是在这种情况下有一些工具可以显示错误:

  1. 如果您想知道您的程序是否访问未初始化的内存,您可以在valgrind下运行它。请注意,这样的检查非常昂贵:在valgrind下,你很容易让你的程序运行更糟,然后慢一个数量级。
  2. 还有clang MemorySanitizer过滤器声称只用3倍减速来完成这项工作,但是你需要在使用clang之前将fortran程序翻译成C(例如用f2c),因为它是C / C ++编译器。您还需要编译程序使用的所有库以及启用此过滤器的clang。