2013-11-09 114 views
0

我是FORTRAN的絕對初學者,並且爲了我自己的使用而苦心地將1000行FORTRAN源文件轉換爲MATLAB。到目前爲止,我一直在通過放入大量PRINT報表來記錄變量並確保數學運行正常。我在FORTRAN中遇到了一個奇怪的事情,我無法解決這個問題。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分配子程序,但他們不應該是相關的。第一次定義數組是在這個子程序中。對於我的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下編譯它們。謝謝你的時間。

+1

回覆:公用塊無關緊要,請注意,如果該符號是一個公共塊,某個其他程序單元可能會用不同的符號名稱訪問該公用塊。 – agentp

+0

'ij''ijt'循環在哪裏? – ja72

+0

@george:我確實注意到了其他變量的這種行爲。唯一我不確定的是如何知道使用它是什麼,因爲這是第一次定義'ab1'。 @ ja72'ij'' ijt'循環的定義如下所示。 'ij = kmv-1,if(ij.lt.0),ij = 0 ijt = 2 * ij'所以沒什麼太花哨。 –

回答

1

只是想知道:你會期待什麼呢?

這些值來自內存。當你調用一個定義變量的東西(函數/程序/子程序)時,某些內存與定義的變量相關聯,但是直到你給變量賦值之前,它將使用之前存在於內存中的任何東西。由於計算機內存不斷重複使用而不被重置,因此可能會從其他名爲已經結束的函數/子例程的變量中獲得值,而來自其他進程的一塊內存(除了必須由內核清空的某些頁面他們可能包含私人數據)或其他任何東西。一般的規則是,沒有人會像設置內存那樣昂貴的操作,除非他致命地需要這樣的內存(例如,在這裏你可以設置與變量相關的內存給你需要的數字,或者當不擦除內存時是潛在的安全缺陷) 。

總結:這些值來自未初始化的內存。確切的內容是未定義的。

在訪問未初始化的內存時不會出錯,因爲檢查內存是否已初始化是非常昂貴的操作。但也有工具,會告訴你的錯誤在這種情況下:

  1. 如果你想知道你的程序是否訪問未初始化的內存可能valgrind下運行它。請注意,這樣的檢查非常昂貴:在valgrind下,您的程序運行會變得更糟,然後降低一個數量級。
  2. 也有叮鐺聲MemorySanitizer過濾器聲稱做這個工作只有3倍放緩,但你需要翻譯fortran程序到C(例如用f2c)之前使用鐺,因爲它是C/C++編譯器。您還需要在啓用此過濾器的情況下編譯您的程序使用的所有庫。
+0

Fortran編譯器(我熟悉的編譯器)可以識別使用未初始化的變量,'valgrind'對於這樣一個簡單的任務幾乎不需要。 –

+0

@HighPerformanceMark在這裏:也許吧。一般來說:不。考慮調用另一個文件中定義的子例程,爲其提供未初始化的變量並分別編譯這些文件的情況。編譯調用程序的編譯器實例不知道您是想要路徑值還是通常用於低級語言返回值參數中的情況。編譯調用對象的編譯器實例不知道子例程是否會傳遞初始化或未初始化的內存。鏈接器根本不在乎,也無法檢測到這種情況。因此你將不得不使用valgrind。 – ZyX

+0

嗨ZyX。我在C++中確實有一些背景知識,所以它可能會讀取內存值這一事實超出了我的想法。不過,我今天早上剛剛打開了電腦,並再次運行該程序,並使用'ab1(107.500008,5.38305187)'。所以它和以前的會議相同。我認爲這對於垃圾值來說不太可能。注意這是FORTRAN 77標準,如果這有助於任何事情。我會嘗試valgrind雖然... –

2

ab1是小數組(50 * 8 = 400字節),因此很可能分配在程序堆棧上。無論何時調用子例程,堆棧都用於存儲局部變量以及調用者的返回地址。最初,堆棧頁面包含全部零,但隨着子程序被調用它增長並填充一些數字。稍後當子例程返回時,堆棧指針被改變,但是這些值仍然在堆棧上,並被新的調用覆蓋。當ab1被分配時,其存儲器最初將填充來自先前稱爲子例程的舊堆棧值。大多數FORTRAN編譯器不會默認生成初始化堆棧變量的指令,因爲它可能是一個昂貴的操作。

如果你的程序是完全確定性的,即沒有子程序調用取決於某些(僞)隨機數的值或者初始PRNG種子總是相同的,那麼就無法返回地址的所有其他內容你的程序的許多執行之間的堆棧將會是相同的,例如一個在晚上,一個在早上。

這就是爲什麼SUM(ab1)總是返回(107.500008, 5.38305187)。它實際上是一個GoodThing(tm) - 它表明你的計算機是一個確定性的設備,即它給出了相同的算法和相同的輸入,因此可用於執行編程任務。這也是一個BadThing(tm),因爲可預測的堆棧值存在於許多針對操作系統安全性的攻擊的基礎上,但這遠遠超出了問題的範圍。