8

Fortran 90で2つのベクトルの外積を計算したいと思います。たとえば、(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は、関数定義の最後から2番目の行にステートメントが配置されています。これを試しましたが、元のランクの不一致エラーが発生します。

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

    したがって、これで問題が解決するわけではありません。

私のエラーを確認するのを手伝ってくれませんか。

4

3 に答える 3

22

ベストプラクティスは、プロシージャ(サブルーチンと関数)をモジュールに配置してから、メインプログラムまたは他のプロシージャからそのモジュールを「使用」することです。同じモジュールの他の手順からモジュールを「使用」する必要はありません。これにより、プロシージャのインターフェイスが明示的になり、呼び出し元のプログラムまたはプロシージャが引数の特性を「認識」します。これにより、コンパイラは両側の引数間の整合性をチェックできます...呼び出し元と呼び出し先..これ多くのバグを排除します。

言語標準の範囲外ですが、実際には必要です。1つのファイルを使用する場合は、それを使用するメインプログラムの前にモジュールを配置します。そうしないと、コンパイラはそれを認識しません。それで:

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ですが、2つの引数を指定したため、エラーが発生します

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

これは、コンパイラが1つを予期していたときに2つの座標を指定したことを意味します。

于 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 に答える