2013-11-09 4 views
0

Я являюсь абсолютным новичком в 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 

Существует немного более common и dimension распределения ниже, но они не должны быть актуальными. В первый раз, когда определен массив 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). Это сложное число, так что два значения являются точными, но что не замечательно в том, что у него есть что-то в нем вообще? Infact единственный раз, когда используется ab1, находится в этом блоке кода.

Есть ли что-нибудь, что мне не хватает здесь? Я просмотрел исходный файл (ctrl-f: ab1), чтобы найти его. Исходный источник - это .for-файл, и я скомпилировал их в Eclipse с помощью gfortran. Спасибо за ваше время.

+1

re: общие блоки неактуальны, имейте в виду, если символ является общим блоком, некоторые другие программные единицы могут получить доступ к этому общему блоку с разными именами символов. – agentp

+0

Где находится цикл 'ij'' ijt'? – ja72

+0

@george: Я заметил это поведение от других переменных. Единственное, что я не уверен в том, как узнать, что его использует, поскольку это первый раз, когда определен 'ab1'. @ ja72 Цикл 'ij'' ijt' определен немного раньше, как показано ниже. 'ij = kmv-1, если (ij.lt.0), ij = 0 ijt = 2 * ij', поэтому ничего необычного. –

ответ

1

Просто интересно: что вы ожидаете там вместо этого?

Эти значения взяты из памяти. Когда вы вызываете что-то (function/program/subroutine), которое определяет переменную, какая-то часть памяти связана с определенной переменной, но пока вы не назначите что-то переменной, она будет использовать все, что было в памяти раньше. Поскольку компьютерная память постоянно используется повторно без сброса, вы можете получить там значение от переменной из другой вызываемой функции/подпрограммы, которая уже закончилась, часть памяти из другого процесса (за исключением некоторых страниц, которые должны быть опустошены ядром как они могут содержать личные данные) или что-то еще. Общее правило заключается в том, что никто не будет делать такую ​​дорогостоящую операцию, как установка памяти на какое-то значение, если он не нуждается в этом смертельно (например, здесь, где вы устанавливаете память, связанную с переменными, в нужные вам числа или когда не стираете память, это потенциальная ошибка безопасности) ,

Вкратце: эти значения взяты из неинициализированной памяти. Точное содержимое не определено.

Вы не получаете ошибок при доступе к неинициализированной памяти, так как проверка инициализации памяти - очень дорогостоящая операция. Но есть инструменты, которые будут показывать вам ошибки в этом случае:

  1. Если вы хотите знать, обращается ли ваша программа неинициализированный памяти, вы можете запустить его под valgrind. Обратите внимание, что такие проверки очень дороги: под valgrind вы легко получаете свою программу, которая работает хуже, чем на порядок медленнее.
  2. Существует также clang MemorySanitizer фильтр, который утверждает, что выполняет эту работу только с 3-кратным замедлением, но вам нужно будет перевести программу fortran на C (например, с f2c), прежде чем использовать clang, поскольку это компилятор C/C++.Вам также необходимо скомпилировать все библиотеки, используемые вашей программой, с clang с включенным фильтром.
+0

Компиляторы Fortran (те, с которыми я знаком) могут идентифицировать использование неинициализированных переменных, 'valgrind' едва ли необходим для такой простой задачи. –

+0

@HighPerformanceMark Здесь: может быть. В общем: нет. Рассмотрим случай, когда вы вызываете подпрограмму, определенную в другом файле, снабжая ее неинициализированной переменной и компилируя эти файлы отдельно. Экземпляр компилятора, который компилирует вызывающий объект, не знает, предназначено ли вы для указания значения или обычно для ситуации с возвратом-значением в аргументах низкого уровня. Экземпляр компилятора, который компилирует вызываемый, не знает, будет ли подпрограмма передаваться инициализированной или неинициализированной памяти. Линкером просто все равно, и у него нет средств для обнаружения такой ситуации. Таким образом, вам придется использовать valgrind. – ZyX

+0

Hi 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), поскольку прогнозируемые значения стека лежат в основе многих атак на безопасность ОС, но это выходит за рамки вашей проблемы.

Смежные вопросы