Передача длины массива в функцию

Извините, если это тривиальный вопрос. Мой фортран-фу беден.

Есть ли способ в fortran для пути длины массива? Также используется опция common (которая, как я понимаю, эквивалентна global ). Я хочу, чтобы в основной программе вызывается функция с массивом. Например (это вводится, а не копировать пасту из любого места)

program prog
integer num
double precision x(num),v
double precision test

....
v=test(x,num)
....


function test(x,num)
double precision test
integer num
double precision x(num)
test=0.0d0
....
return
end

Это не будет компилироваться, поскольку num не является константой. Важно знать, что это размер массива, который я передаю.

Edit: Я использую компилятор f95.

Edit2: Я попробовал решение High Performance Mark без везения:

  program prog
  integer v
  parameter (v=10)
  double precision x(v),test,k
  k=test(x)
  write (*,*) size(x)
  stop
  end

  function test(x)
  double precision, dimension(:),intent(in) :: x
  double precision test
  write (*,*) size(x)
  test = 0.0d0
  return
  end

Вывод должен быть двух строк, где записаны 10 и 10. Вместо этого я получил это:

/scpc:niels: #$ f95 err.f
/scpc:niels: #$ ./a.out 
           0
          10
/scpc:niels: #$ 
2
nl ja de
@VladimirF Спасибо за ваши комментарии. Я использую то же самое, что и Emacs. Как четыре ваших других комментария, я обновляю код adivsor, и мой fortran-fu низкий. Я подозреваю, что я наберу больше урона, чем хорошо, если я попытаюсь это сделать.
добавлено автор Yotam, источник
Другой стиль комментирует рядом с общими блоками. Нет причин использовать «stop» или «return» перед «end». double precision следует избегать и изменять на real (rp) , где rp может быть rp = kind (1d.0) для простоты или вы используете selected_real_kind . Также код тура отступа!
добавлено автор Vladimir F, источник

2 ответы

Массивы Fortran «знают», как долго они находятся, вам не нужно передавать массив и его длину как разные аргументы. (Если, конечно, вы не взаимодействуете со старыми кодами Фортрана.) Сегодня вы должны написать что-то вроде этого

function test(arr)
    real, dimension(:), intent(in) :: arr
    ...
    integer :: arrsize
    ...
    arrsize = size(arr)
    ...

Если вам нужно взаимодействовать со старым кодом, в котором пройдены размеры массива, вы можете совершать такие вызовы

  call old_fortran_subr(array, size(array, 1), other_arguments)

О, и, хотя я пишу, не имеет ничего общего с common в любом коде, который вы пишете с нуля, это (по праву) устаревшая функция с 70-х и ранее. Вместо этого используйте переменные модуля .

9
добавлено
Я пробовал это без везения. Я отредактировал мой вопрос с тем, что я сделал. Где я могу прочитать о переменных модуля?
добавлено автор Yotam, источник
Кто знает, из какой версии Fortran обязательная необходимость явного объявления массива, переданного в качестве параметров для подпрограмм, удаляется? т. е. нам просто нужно объявить «real, dimension (:, :) :: arr», а не «real, dimension (3,5) :: arr». Поскольку @HighPerformanceMark сказал, что нам нужно, чтобы первый взаимодействовал с OLD-файлами Fortran, это Fortran 77?
добавлено автор wiswit, источник
+1 Только для последнего предложения. Общих блоков следует избегать, как чуму, в любом даже неопределенно современном диалекте Фортрана.
добавлено автор talonmies, источник
Мой компилятор (Intel Fortran 13.0) компилирует ваш новый код и дважды записывает 10 . Либо то, что вы опубликовали, не является верной копией вашего кода, либо у вас проблемы, которые я не вижу.
добавлено автор High Performance Mark, источник
Вы можете прочитать о переменных модуля прямо здесь, на SO, среди других мест.
добавлено автор High Performance Mark, источник
Что касается переменных модуля, тогда как они менее плохи, чем обычные, все равно избегайте их, где это возможно. Глобальные переменные упрощают обслуживание и разработку кода, на самом деле хорошей практикой является сокращение объема переменных как можно меньше, и это сэкономит ваше время и энергию в долгосрочной перспективе.
добавлено автор Ian Bush, источник
@Yotam: у вас есть массив предполагаемых форм ( dimension (:) ) фиктивный аргумент в вашей функции, для которого требуется «явный интерфейс». Самый простой способ обеспечить это - сделать вашу функцию внутренней процедурой программы или модуля, который вы используете в программе.
добавлено автор sigma, источник

Хорошо, здесь многое происходит, тем более, что стиль Fortran, который вы используете, немного архаичен. Давайте сделаем это пошагово ...

Во-первых, убедитесь, что вы всегда используете неявный

Во-вторых, если вы знаете размер массива априори, вы можете использовать символическую константу для обозначения ее размера. Вы делаете это с помощью параметра:

Program prog

  Implicit None ! ALWAYS USE THIS

  Integer, Parameter :: num = 36

  Double Precision x( num )
  Double Precision test
  Double Precision v

  Call Random_number( x )

  v = test( x, num )

  Write( *, * ) v

End Program prog

Function test( x, num )

  Implicit None ! ALWAYS USE THIS

  Double Precision test

  Integer num
  Double Precision x( num )

  Integer i

  test = 0.0d0
  Do i = 1, num
     test = test + x( i ) * x( i )
  End Do

End Function test
[[email protected] stackoverflow]$ gfortran -O -std=f95 -Wall -Wextra -pedantic func.f90
[[email protected] stackoverflow]$ ./a.out
   12.129812171430215     

Обратите внимание, как num установлено равным 36, но бит параметра означает, что я не могу изменить его значение - он является константой и поэтому может использоваться для установки размера массивов.

И так обстояло дело до 1990 года. Затем на язык, который менял ответ, вошел ряд вещей. Большинство напрямую связанных с вашим вопросом - это выделяемые массивы, которые позволяют указать размер массива во время выполнения и предполагаемые массивы форм, которые упрощают прохождение массивов в подпрограммах. Однако вошло множество других вещей, и я предлагаю вам ознакомиться с книгой, чтобы узнать о них - новый язык гораздо более выразителен и безопаснее старого. В качестве примера я бы написал выше в наше время как нечто вроде

[[email protected] stackoverflow]$ cat func.f90

Module numbers_module

  Integer, Parameter :: wp = Selected_real_kind( 12, 70 )

End Module numbers_module

    Module funcs_module

      Use numbers_module

      Implicit None

      Public :: test

      Private

    Contains

      Function test( x ) Result( sum_sq )

        Implicit None ! ALWAYS USE THIS

        Real( wp ) :: sum_sq

        Real( wp ), Dimension( : ), Intent( In ) :: x

        sum_sq = Sum( x * x )

      End Function test

    End Module funcs_module

    Program prog

      Use numbers_module
      Use funcs_module

      Implicit None ! ALWAYS USE THIS

      Real( wp ), Dimension( : ), Allocatable :: x 

      Real( wp ) :: v

      Integer :: num

      Write( *, * ) 'How many elements ?'
      Read ( *, * ) num
      Allocate( x( 1:num ) )

      Call Random_number( x )

      v = test( x )

      Write( *, * ) v

    End Program prog

    [[email protected] stackoverflow]$ gfortran -O -std=f95 -Wall -Wextra -pedantic func.f90
    [[email protected] stackoverflow]$ ./a.out
     How many elements ?
    39
       14.151818513394156  

Если вы решите пойти этим путем, убедитесь, что вы понимаете, зачем использовать этот метод, интерфейс для тестирования должен находиться в области действия в вызывающей точке - и для этого читайте книгу.

Ой. Общие. Просто сказать нет.

2
добавлено