2011-08-03 8 views
3

私はFortran初心者です。私はメインプログラムから4つの引数を取るサブルーチンを書こうとしています。そして、最初に渡された4つの引数を含む配列をメインプログラムに出力します。これを行うには何が良い方法ですか?Fortran 90で引数を渡すスマートな方法

は例えば、以下の私のテストプログラムでは、私は、メインプログラムの4つの実数変数を(abc、およびd)を作成します。次に、これらの実変数をmysubというサブルーチンに渡します。 mysubabc、およびdに入れて、oという2行2列の配列を作成し、oをメインプログラムに送信して(可能な変更を行う)ことができますようにします。だから、私は次のことを試してみました:

SUBROUTINE mysub(w,x,y,z) 
    IMPLICIT NONE 
    REAL, INTENT(IN) :: w, x, y, z 
    REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o 

    ALLOCATE(o(2,2)) 
    o(1,1)=w 
    o(1,2)=x 
    o(2,1)=y 
    o(2,2)=z 
END SUBROUTINE mysub 
END MODULE testsubs 

PROGRAM test 
    USE testsubs 
    IMPLICIT NONE 
    REAL :: a=1.1, b=2.2, c=3.3, d=4.4 

    CALL mysub(a, b, c, d) 

    PRINT *, o(1,1), o(1,2) 
    PRINT *, o(2,1), o(2,2) 
END PROGRAM test 

しかし、私は次のエラーを取得する:oはしていないので、

test.f90:10.53: 

    REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o 
                1 
Error: Symbol at (1) is not a DUMMY variable 

私はこれを解釈し、コンパイラは、oが何であるかを知りませんサブルーチンヘッダの引数リスト:SUBROUTINE mysub(w,x,y,z)だから、おそらくそのヘッダにoを含める必要があります。だから、私は次の(私は!...を使用して変更や追加を表記している)、次の試してみてください。

SUBROUTINE mysub(w,x,y,z,o) !... 
    IMPLICIT NONE 
    REAL, INTENT(IN) :: w, x, y, z 
    REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o 

    ALLOCATE(o(2,2)) 
    o(1,1)=w 
    o(1,2)=x 
    o(2,1)=y 
    o(2,2)=z 
END SUBROUTINE mysub 
END MODULE testsubs 

PROGRAM test 
    USE testsubs 
    IMPLICIT NONE 
    REAL :: a=1.1, b=2.2, c=3.3, d=4.4 
    REAL, DIMENSION(:,:), ALLOCATABLE :: o !... 

    CALL mysub(a, b, c, d, o) !... 

    PRINT *, o(1,1), o(1,2) 
    PRINT *, o(2,1), o(2,2) 
    DEALLOCATE(o) !... 
END PROGRAM test 

これは正常に動作するようですが、私は正しい出力を得る:

1.1000000  2.2000000 
    3.3000000  4.4000001 

しかし、私の質問をこれを行うには良い方法ですか?この例では、配列oと、メインプログラムのの両方にと宣言しています。私はこれは私がどちらかサブルーチンまたはは、メインプログラムは(エラーメッセージを避けるために、私は思いますが、ない両方)oを割り当てる世話をする必要があることを意味していることだと思うので、これは、潜在的に混乱を招くようです。サブルーチンからメインプログラムに配列を送るには、よりスマートな方法がありますか?あなたの時間をありがとう。あなたは、配列を返すようにしたい場合は

答えて

3

あなたの解決策は、 "o"を意図(out)引数にすることです。 "o"が引数でなければ、サブルーチンの変数 "o"とメインプログラムの変数 "o"との間には接続がないため、メインプログラムには宣言や割り当てはありませんでした。さらに別の解決策(@ ja72が提供するもののほかに)はあなたのメソッドを変更することです:サブルーチンの意図(inout)引数を "o"にして、それをメインプログラムに割り当てます。可能な利点:allocateとdeallocateはコード内で互いに接近してペアになっています。考えられる欠点:プログラムのロジックとデザインによっては、配列の寸法がサブルーチンに最もよく知られている可能性があります。

P.S.メインプログラムで配列を割り当て、サブルーチンで配列の割り当て可能なプロパティを実際に使用していない場合(つまり、割り付けたり割り当てを解除したりしない場合)、allocatable属性で宣言する必要はありませんサブルーチンで - 有用な単純化。この場合、「意図(アウト)」が適切かもしれません。しかし、メインプログラムで配列を割り当てて、その状態をサブルーチンに渡したい場合、引数の状態は "意図していません"。 "intent(out)"は、プロシージャへのエントリ時に自動的に引数の割り当てを解除します。

1

あなたは、a)は、サブ以内に配分してあなたの例#2のようにINTENT(OUT)を引数に追加することができ、またはb)関数を作成し、外部配列を割り当てる:

FUNCTION myfun(w,x,y,z,n,m) 
IMPLICIT NONE 
INTEGER, INTENT(IN) :: n,m 
REAL, DIMENSION(n,m) :: myfun 
REAL, INTENT(IN) :: w,x,y,z 

    myfun(1,1)=w 
    myfun(1,2)=x 
    myfun(2,1)=y 
    myfun(2,2)=z 

END FUNCTION 
END MODULE testsubs 

PROGRAM test 
    USE testsubs 
    IMPLICIT NONE 
    REAL :: a=1.1, b=2.2, c=3.3, d=4.4 
    REAL, DIMENSION(:,:), ALLOCATABLE :: o !... 

    ALLOCATE(o(2,2)) 
    o = myfun(a,b,c,d,2,2) 

    PRINT *, o(1,1), o(1,2) 
    PRINT *, o(2,1), o(2,2) 
    DEALLOCATE(o) !... 
END PROGRAM test 

実際、あなたのソリューションはよりクリーンだと思います。

1

配列のサイズを事前に知っているかどうかは分かりませんが、そうした場合、通常は同じ場所に配列を割り当てたり割り当てを解除したりすることをお勧めします可能であればコンパイラにメモリを割り当てさせる。

私はどうなる方法:サイズはコンパイル時に知られている

  • 場合: は、メインプログラムであなたの配列を宣言し、サブルーチンでintent(out)を使用しています。

  • サイズは、実行時にのみ知らされている場合: は、メインプログラムのサブルーチンとDEALLOCATEでintent(out)を使用し、メインプログラムに割り当てます。

出力はコピーする必要があるため、機能は小さな出力に最適です。

関連する問題