2011-06-28 369 views
5

Fortran 90で2つのベクトルの外積を計算したいとします。たとえば、(1,2,3)と(4,5 、6)はデカルト座標で(-3,6、-3)となる。Fortran 90で2つのベクトルの外積を計算する

crosstest.f90:10.9: 

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

ライン10はr=cross(m,n)です:私は、エラーメッセージを取得し、

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 

しかし:私は、次のコード(関数の定義に続いて、メインプログラム)を書きました。間違って次元を指定する必要があるようです。ここで私が持っているいくつかのアイデアです:

  1. おそらく、メインプログラム内の関数crossの宣言は、単純に整数の変数ではなく、1by3整数配列でなければなりません。そこで、メインプログラムのINTEGER, DIMENSION(3) :: cross行にある, DIMENSION(3)を削除しようとしました。しかし、エラーメッセージが表示されます。

    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. Web上の一部のFortran関数の例には、関数定義の最後から2番目の行にRETURN文が追加されています。これを試しましたが、元のランクの不一致エラーが発生します。

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

    これで問題は解決しません。

あなたは私のエラーを見ることができます!

答えて

19

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

言語標準の外ですが、実際には必要です。ファイルを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 
+0

お時間をありがとうございました! – Andrew

+3

+1(より醜い) '(1、2、3 \)'の代わりに '[1,2,3]'を使うために+1してください。 –

5

これは後半の答えのようなものですが、私はこれにつまずいたし、あなたのエラーが発生した原因についてはまだ本当の説明がないので、私は時につまずく他のみんなのために説明を追加したい考え出し

プログラムでは、ランク1のcrossという配列を定義します。次に定義するcross関数を呼び出します。cross関数は明示的なインタフェースを持たないので(M.S.B.の答えを参照)、この時点ではコンパイラはそれを知りません。それが知っていることはあなたが宣言した配列です。 r = cross(m, n)と書くと、コンパイラは配列crossの位置(m、n)の要素にアクセスすると考えます。この配列は、ランク1であるが、あなたは二つの引数を与えているので、あなたはコンパイラが1を期待していたときに2点の座標を供給することを意味している

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

エラーが発生します。

+0

ありがとうございます。それは理にかなっている。私はそれに応じて答えを編集しました。 – toster

関連する問題