Вычисление перекрестного произведения двух векторов в Фортране 90 - PullRequest
7 голосов
/ 28 июня 2011

Я хотел бы вычислить перекрестное произведение двух векторов в Фортране-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 в Интернете размещают RETURNоператор в последней строке определения функции.Я пробовал это, но я получаю оригинальную ошибку несоответствия ранга:

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

    Так что это не решает проблему.

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

Ответы [ 2 ]

20 голосов
/ 29 июня 2011

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

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

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
6 голосов
/ 14 ноября 2015

Это своего рода поздний ответ, но так как я наткнулся на это, и пока нет реального объяснения, почему произошла ваша ошибка, я решил добавить объяснение всем остальным, кто наткнулся на этот вопрос:

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...