5

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

たとえば、以下のテスト プログラムでは、メイン プログラムで4 つの実数変数 ( abc、および) を作成します。d次に、これらの実数変数を というサブルーチンに渡しますmysub。、、、およびをmysub取り込み、それらを使用して と呼ばれる 2 行 2 列の配列を設定し、メイン プログラムに送信してそこで表示 (および可能な変更) できるようにしたいと考えています。だから、私は次のことを試しました:abcdoo

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

しかし、次のエラーが表示されます。

test.f90:10.53:

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

私はこれを、サブルーチンヘッダーの引数のリストにないoため、コンパイラーが何であるかを知らないと解釈します: . したがって、おそらくそのヘッダーに含める必要があります。そこで、次に次のことを試します (ここでは、 を使用して変更または追加を示しています)。oSUBROUTINE 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

4

3 に答える 3

4

「o」をintent(out)引数にするという解決策は、問題ありません。「o」が引数でないと、サブルーチンの変数「o」とメインプログラムの変数「o」の間に接続がなかったため、メインプログラムの変数の宣言または割り当てはありませんでした。さらに別の解決策(@ ja72によって提供されるもの以外)は、メソッドを変更することです。「o」をサブルーチンのintent(inout)引数にして、メインプログラムに割り当てます。考えられる利点:割り当てと割り当て解除は、コード内で互いに近く、ペアになっています。考えられる欠点:プログラムのロジックと設計によっては、配列の次元がサブルーチンに最もよく知られている場合があります。

PSメインプログラムで配列を割り当て、サブルーチンで配列の割り当て可能なプロパティを実際に使用しない場合(つまり、配列を割り当てたり、割り当てを解除したりしない場合)、割り当て可能な配列で宣言する必要はありません。サブルーチンの属性-便利な簡略化。その場合、「意図(アウト)」が適切かもしれません。ただし、メインプログラムで配列を割り当て、そのステータスをサブルーチンに渡したい場合は、引数のステータスを「intent(out)」にすることはできません。「intent(out)」は、プロシージャに入ると自動的に引数の割り当てを解除します。

于 2011-08-03T21:01:12.717 に答える
1

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

私のやり方:

  • コンパイル時にサイズがわかっている場合: メインプログラムで配列を宣言intent(out)し、サブルーチンで使用します。

  • サイズが実行時にのみわかっている場合:intent(out)メインプログラムで割り当て、サブルーチン で使用し、メインプログラムで割り当てを解除します。

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

于 2011-08-03T21:05:38.863 に答える
1

配列を返したい場合は、a)INTENT(OUT)例 #2 のようにサブ内に割り当てて引数に追加するか、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

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

于 2011-08-03T20:29:16.227 に答える