2017-08-30 17 views
1

元の質問

私が理解しているように、Fortran 95のステートメント機能は、内部機能のために時代遅れと宣言されています。しかし、内部関数はすべてのユースケースを網羅しておらず、特に長い式の実装をより読みやすくするための暗黙の引数を持つ略語としての文関数を使用する場合はそうではありません。このユースケースを適切に置き換えることはできますか?Fortran 95以降で廃止された「ステートメント機能」の置き換え?

例えば、我々が関係を持って言うことができます

                Cᵢⱼ=∫dx₁∫dx₂∫dx₃∫dy₁∫dy₂∫dy₃(AᵢⱼBᵢⱼ+BᵢⱼAⱼᵢ)

例第二に

A(i,j) = ARR_A(x1,x2,x3,i,y1,y2,y3,j) 
B(i,j) = ARR_B(x1,x2,x3,i,y1,y2,y3,j) 
... 
do x1=1,NGRID1; do x2=1,NGRID2; ...; do y3=1,NGRIDN 
    x(i,j) = x(i,j) + A(i,j)*B(i,j) + B(i,j)*A(i,j) 
end do; end do; ...; end do 

、略語として文関数を使用して実装する

do a1=1,NGRID1; do a2=1,NGRID2; ...; do aN=1,NGRIDN 
    x(i,j) = x(i,j) & 
     & + ARR_A(x1,x2,x3,i,y1,y2,y3,j)*ARR_B(x1,x2,x3,i,y1,y2,y3,j) & 
     & + ARR_B(x1,x2,x3,i,y1,y2,y3,j)*ARR_A(x1,x2,x3,i,y1,y2,y3,j) 
end do; end do; ...; end do 

その結果、前のコードで義務付けインデックス順序と直接A、Bの内部表現を使用して実装を比較バージョンであることに気づいた後で、インデックスの混在した順序を見つけるのがはるかに簡単に思えるようです。

マクロを使用していますか?

私が見つけた同様のセマンティクスを実現する唯一の方法は、プリプロセッサマクロの使用でした。一般的に、Cスタイルのマクロはここ

#define A(i,j) ARR_A(x1,x2,x3,i,y1,y2,y3,j) 

が、名前のこの犠牲スコープにつながるれ、使用されています。これは潜在的に有用であると思われるが、特に複数の機能にわたって同じ略語が使用される場合、潜在的には混乱する可能性がある。まず、ステートメント関数をマクロ用に誤って使用すると、コンパイラーはより有用なエラーメッセージを出します。

また、別のコンテキストで同じ名前を別のものに再利用したい場合は、手動で名前を入力する必要があります。

ソリューション(1)

私はCONTAINSと内部関数がどのように動作するかを誤解していた(IanH's answerとそのコメントを参照してください)。

短い:内部関数は、CONTAINSのサブルーチン内で定義することができ、より冗長な構文を除いて、文関数とまったく同じ働きをします。

明らかに、 ではないので、誤解が生じました。では、このようにサブルーチンを定義することはできません。 明らかに動作します。私が間違って何をしているのか分かりません。

+1

なぜ内部関数がこのユースケースをカバーしていないのですか? – IanH

+0

おもちゃの例ですが、あなたはちょうど '2 * A(i、j)* B(i、j)'を実行することができます – agentp

+0

あなたは間違っています。サブルーチンの中にサブルーチンを定義することは完全に可能です。 –

答えて

4

内部プロシージャは、通常のメリットとエラーの可能性の低い通常のメリットを使用して、この使用例の文機能を置き換えるものです。

MODULE some_module  ! Just for the sake of example. 
    ... 
CONTAINS 
    ! The host of the internal procedure. This could 
    ! also be an external procedure or a main program. 
    ! It could also be a function. 
    SUBROUTINE some_subroutine 
    ... 
    DO i = 1, 3 
     DO j = 1, 3 
     DO x1 = 1, 3 
      DO x2 = 1, 3 
      ... 
      x(i,j) = x(i,j) + A(i,j)*B(i,j) + B(i,j)*A(i,j) 
      ... 
      END DO 
     END DO 
     END DO 
    END DO  
    ...  
    CONTAINS 
    ! An internal procedure. For different use cases 
    ! this could also be a subroutine. 
    FUNCTION A(i,j) 
     INTEGER, INTENT(IN) :: i,j 
     REAL :: A 
     A = ARR_A(x1,x2,x3,i,y1,y2,y3,j) 
    END FUNCTION A 

    FUNCTION B(i,j) 
     INTEGER, INTENT(IN) :: i,j 
     REAL :: B 
     B = ARR_B(x1,x2,x3,i,y1,y2,y3,j) 
    END FUNCTION B 
    ... 
END SUBROUTINE some_subroutine 
... 
END MODULE some_module 

Fortran 77/90/95/2003のルールに基づく最大配列ランクは7です。

+0

これはうまくいきますが、これはかなり普遍的に悩まされているグローバル変数( 'PROGRAM'や' MODULE'のレベル) Fortranの外にあります。特に、サブルーチンの中に省略形が必要な場合は、その範囲を必要な場所に限定することができます。ループ変数をグローバルにする(フラグが "private"になっていても)、混乱を招く可能性があります。 Statement関数は、サブルーチン内で定義することでこれを可能にします。内部機能では、私のモジュールをいくつかのモジュールに分けて、似たようなものを実現する必要があります。 – kdb

+0

私はあなたが内部の手順を誤解していると思います。内部プロシージャに関連付けられたホストの変数のスコープは、ステートメント関数に関連付けられた変数のスコープとまったく同じ*です。内部プロシージャーはホストプロシージャーの内部で定義されています - そのため、内部プロシージャーは "内部"と呼ばれています! – IanH

+0

それは私が問題を理解したようだ。私はサブルーチンの中の 'CONTAINS'がモジュール内の' COTAINS 'と同じものを許すことを期待していましたが、ネストされたサブルーチンを定義することはできません。私はまた、混乱につながった副作用のための関数を '呼び出す 'ことは許されていないことも認識していませんでした。 – kdb

関連する問題