8

我想在 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主程序中函数的声明应该只是一个整数变量,而不是一个 1×3 整数数组。所以我尝试在主程序中删除该行, 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. Web 上的一些(但不是全部)Fortran 函数示例在EXTERNAL主程序中的函数声明之后放置了一条语句。EXTERNAL cross所以我尝试在主程序的声明块之后放置一行。我收到一条错误消息:

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

    所以这似乎也不正确。

  3. Web 上的一些(但不是全部)Fortran 函数示例在RETURN函数定义的倒数第二行放置了一条语句。我试过这个,但我得到了原来的排名不匹配错误:

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

    所以这并不能解决问题。

你能帮我看看我的错误吗?

4

3 回答 3

22

最佳实践是将您的程序(子程序和函数)放在一个模块中,然后从您的主程序或其他程序中“使用”该模块。您不需要从同一模块的其他过程中“使用”该模块。这将使过程的接口显式,以便调用程序或过程“知道”参数的特征......它允许编译器检查双方参数之间的一致性......调用者和被调用者..这个消除了很多错误。

在语言标准之外,但在实践中是必要的:如果您使用一个文件,请将模块放在使用它的主程序之前。否则编译器将不知道它。所以:

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
于 2011-06-28T20:17:08.120 回答
7

这是一个迟到的答案,但是由于我偶然发现了这个并且还没有真正解释为什么你的错误发生了,我想我会为其他偶然发现这个问题的人添加一个解释:

在您的程序中,您定义了一个名为 的数组cross,它的等级为 1。然后您调用cross您定义的函数进一步向下。由于该cross函数没有显式接口(请参阅 MSB 的答案),因此编译器此时不知道它。它所知道的是您声明的数组。如果你写r = cross(m, n),编译器认为你想访问数组中位置 (m, n) 的元素cross。由于此数组的等级为 1,但您提供了两个参数,因此您会收到错误

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

这意味着您在编译器期望一个坐标时提供了两个坐标。

于 2015-11-14T17:52:44.130 回答
1

您可以将程序中使用的子程序放在程序中的contains关键字之后。这消除了创建模块或添加接口定义的需要。

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)

  print *, r

CONTAINS

PURE 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 PROGRAM crosstest
于 2021-01-06T15:41:46.027 回答