Вычисление векторного произведения двух векторов в 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)
. Кажется, я неправильно указываю измерение. Вот несколько идей у меня есть:
-
возможно объявление функции
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
так это еще хуже, наверное.
-
некоторые (но не все) примеры функций Fortran на веб-сайте
EXTERNAL
оператор после функции декларация в основной программе. Поэтому я попытался разместить строкуEXTERNAL cross
после блока объявления в основной программе. Я получаю сообщение об ошибке:crosstest.f90:8.16: EXTERNAL cross 1 Error: EXTERNAL attribute conflicts with DIMENSION attribute at (1)
так что это тоже кажется неправильным.
-
некоторые (но не все) примеры функций 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)
это означает, что вы указали две координаты, когда компилятор ожидал одну.