Вычисление векторного произведения двух векторов в Fortran 90

я хотел бы, чтобы вычислить векторное произведение двух векторов в Fortran 90. Например, на словах перекрестное произведение (1, 2, 3) и (4, 5, 6) оказывается (-3, 6, -3) в декартовых координатах. Я написал следующий код (Основная программа с последующим определением функции):

PROGRAM crosstest
  IMPLICIT NONE

  INTEGER, DIMENSION(3) :: m, n
  INTEGER, DIMENSION(3) :: cross
  INTEGER, DIMENSION(3) :: r

  m=(/1, 2, 3/)
  n=(/4, 5, 6/)
  r=cross(m,n)

END PROGRAM crosstest

FUNCTION cross(a, b)
  INTEGER, DIMENSION(3) :: cross
  INTEGER, DIMENSION(3), INTENT(IN) :: a, b

  cross(1) = a(2) * b(3) - a(3) * b(2)
  cross(2) = a(3) * b(1) - a(1) * b(3)
  cross(3) = a(1) * b(2) - a(2) * b(1)
END FUNCTION cross

но, я получаю сообщение об ошибке:

crosstest.f90:10.9:

  r=cross(m,n)
         1
Error: Rank mismatch in array reference at (1) (2/1)

где строка 10 r=cross(m,n). Кажется, я неправильно указываю измерение. Вот несколько идей у меня есть:

  1. возможно объявление функции cross в основной программе должна быть просто целочисленная переменная, а не целочисленный массив 1by3. Поэтому я попытался удалить , DIMENSION(3) на INTEGER, DIMENSION(3) :: cross строка в основной программе. Но я получаю сообщение об ошибке:

    crosstest.f90:10.4:
    
      r=cross(m,n)
        1
    Error: The reference to function 'cross' at (1) either needs an
    explicit INTERFACE or the rank is incorrect
    

    так это еще хуже, наверное.

  2. некоторые (но не все) примеры функций Fortran на веб-сайте EXTERNAL оператор после функции декларация в основной программе. Поэтому я попытался разместить строку EXTERNAL cross после блока объявления в основной программе. Я получаю сообщение об ошибке:

    crosstest.f90:8.16:
    
      EXTERNAL cross
                    1
    Error: EXTERNAL attribute conflicts with DIMENSION attribute at (1)
    

    так что это тоже кажется неправильным.

  3. некоторые (но не все) примеры функций Fortran в веб-месте a RETURN оператор в предпоследней строке определения функции. Я пробовал это, но я получаю исходную ошибку несоответствия ранга:

    crosstest.f90:10.9:
    
      r=cross(m,n)
             1
    Error: Rank mismatch in array reference at (1) (2/1)
    

    так это не исправить проблема.

не могли бы вы помочь мне увидеть мою ошибку?

2 ответов


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

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

module my_subs

implicit none

contains

FUNCTION cross(a, b)
  INTEGER, DIMENSION(3) :: cross
  INTEGER, DIMENSION(3), INTENT(IN) :: a, b

  cross(1) = a(2) * b(3) - a(3) * b(2)
  cross(2) = a(3) * b(1) - a(1) * b(3)
  cross(3) = a(1) * b(2) - a(2) * b(1)
END FUNCTION cross

end module my_subs


PROGRAM crosstest
  use my_subs
  IMPLICIT NONE

  INTEGER, DIMENSION(3) :: m, n
  INTEGER, DIMENSION(3) :: r

  m= [ 1, 2, 3 ]
  n= [ 4, 5, 6 ]
  r=cross(m,n)
  write (*, *) r

END PROGRAM crosstest

в вашей программе, вы определяете массив под названием cross, который имеет ранг 1. Тогда вы называете cross функция, которую вы определяете ниже. С cross функция не имеет явного интерфейса (см. ответ M. S. B.), компилятор не знает об этом в этот момент. То, что он знает, - это массив, который вы объявили. Если вы пишете r = cross(m, n), компилятор думает, что вы хотите получить доступ к элементу в позиции (m, n) массива cross. Поскольку этот массив имеет ранг 1, но вы предоставили два аргумента, вы получаете ошибку

rank mismatch in array reference at (1) (2/1)

это означает, что вы указали две координаты, когда компилятор ожидал одну.