4

最新バージョンのFortranで、kindパラメーターをサブプログラムに渡し、これを使用して変数をこの種類に「キャスト」することは可能ですか?例として、次のコードでは、出力する前にデフォルトの整数を16ビット整数に変換しようとしています。

program mwe

! Could use iso_fortran_env definition of int16, but I am stuck with
! old versions of ifort and gfortran.
! use, intrinsic :: iso_fortran_env, only : int16

implicit none

! 16-bit (short) integer kind.
integer, parameter :: int16 = selected_int_kind(15)

call convert_print(123, int16)

contains

  subroutine convert_print(i, ikind)
    implicit none
    integer, intent(in) :: i
    integer, intent(in) :: ikind

    print*, int(i, ikind)

  end subroutine convert_print

end program mwe

このサンプルコードでは、IntelFortranコンパイラは次のように文句を言います。

mwe.f(24):エラー#6238:このコンテキストでは整数定数式が必要です。[IKIND]
...
mwe.f(24):エラー#6683:種類タイプのパラメーターはコンパイル時定数でなければなりません[IKIND]

とgfortranは文句を言う

(1)に固有の「int」の「kind」引数は定数でなければなりません

print*, int(i, int16)もちろん、代わりに使用するprint*, int(i, ikind)と、この場合は問題なく機能します。ただし、convert_print定義されていないモジュールで定義されている場合int16、これは役に立ちません。

種類パラメータを定数としてサブプログラムに渡す方法はありますか?

4

3 に答える 3

5

私も同じ問題を抱えてる。プロシージャへの引数としてkindデータ型を渡すことが許可されていないことは非常に不便です。私の場合、ファイルから行列を読み取り、必要なデータ型のオブジェクトを取得するためのサブルーチンを作成しています。ReadMatrix_int8(…)、ReadMatrix_int16(…)、ReadMatrix_int32(…)、ReadMatrix_int64(…)の4つの異なるサブルーチンを作成する必要がありました。これらは、1行が異なる同じコードにすぎません。

integer(kind=xxxx), allocatable, intent(out) :: matrix(:,:)

サブルーチンを1つだけ記述し、引数としてxxxxを渡すのは理にかなっています。解決策が見つかったらお知らせします。しかし、4つのサブルーチンを作成してから、次のような汎用プロシージャを作成するためのインターフェイスを作成するよりも良い解決策はないのではないかと思います。

interface ReadMatrix
     module procedure ReadMatrix_int8
     module procedure ReadMatrix_int16
     module procedure ReadMatrix_int32
     module procedure ReadMatrix_int64
end interface
于 2013-02-01T18:44:28.067 に答える
3

私が解決できる限り、私がやろうとしていることは、Fortran 2003標準(PDF、4.5 MB)によって明示的に禁止されています。

5.1.2.10PARAMETER属性

名前付き定数は、同じステートメントで以前に定義されているか、以前のステートメントで定義されているか、使用またはホストの関連付けによってアクセス可能にされていない限り、参照されません。

したがって、実行したい変換ごとに関数を定義する必要があるようです。たとえば、次のようになります。

subroutine print_byte(i)
  implicit none
  integer, intent(in) :: i

  print*, int(i, int8)

end subroutine print_byte

subroutine print_short(i)
  implicit none
  integer, intent(in) :: i

  print*, int(i, int16)

end subroutine print_short

subroutine print_long(i)
  implicit none
  integer, intent(in) :: i

  print*, int(i, int32)

end subroutine print_long

明らかに、さまざまな種類の入力引数を受け入れるには、上記のすべてをオーバーロードする必要があります。これは定数を渡すことができないことを回避するための多くの作業のように思われるので、誰かがより良い解決策を持っているなら、私はそれを見たいと思っています。

于 2012-11-06T15:07:56.057 に答える
2

このインテルの専門家が説明と洗練されたソリューションを提供します。私はそれをよりよく説明することができませんでした。完全な引用は次のとおりです。

「ある日、地元の食料品店の通路をさまよっているときに、女性が私をテーブルに招き、「輸入チョコレートを試してみませんか」と尋ねました。テーブルには、リンツ、トブラローネ、 ...ギラデリ?私は女性に、カリフォルニアがユニオンから脱退したかどうかを尋ねました。ギラデリは、イタリアの名前にもかかわらず、サンフランシスコから来たものです。ニューハンプシャーの見晴らしの良い場所から、カリフォルニアは別の国かもしれないと思います。ニューヨーカーの有名なソールスタインバーグ1976年の表紙、「9番街からの世界の眺め」に描かれているように。

(私のブログには十分な任意のリンクがないという警告がありました-これはしばらくの間それらを保持するはずです。)

同様に、Fortran(私がいつそこにたどり着くのか疑問に思っていたに違いありません)では、何かが非常に近くにあるのに、遠くに見えることがあります。少し前に、Win32 Process Status APIの宣言を提供するために、IntelVisualFortran用の新しいモジュールを作成していました。これには、型と定数の宣言、およびAPIルーチンのインターフェイスブロックが含まれ、その一部は新しい型の引数を取ります。自然な傾向は、次のようなものを書くことです。

MODULE psapi
TYPE sometype
some component
END TYPE sometype

INTERFACE
FUNCTION newroutine (arg)
INTEGER :: newroutine
TYPE (sometype) :: arg
END FUNCTION newroutine
END INTERFACE

END MODULE psapi

コンパイルしてコンパイルすると、argの宣言でsometype型が未定義であるというエラーが発生します。「なに?宣言されていないわけではない。同じモジュールの真上で見ることができる!」ええ、はい、いいえ。はい、モジュールで宣言されており、モジュール内のどこでも使用できます。ただし、インターフェイスブロックを除きます。

問題は、インターフェースブロックが「外部ルーチンへのウィンドウ」であるということです。ルーチンがFortranで書かれていると仮定すると、実際の外部ルーチンに表示される宣言を本質的に複製します。そのため、それらは、囲んでいるスコーピングユニット(この場合はモジュール)からのシンボルを「ホストアソシエート」しません。

Fortran90およびFortran95では、これに対する一般的な解決策は、使用するすべての型と定数を含む「psapi_types」などの個別のモジュールを作成することでした。次に、各関数内にUSEステートメントを追加します。あなたはFortranで書かれた架空の外部ルーチンでやらなければならないでしょう。(Fortranで書かれている場合、医者は濡れたパンチカードで手首を叩き、ルーチンをモジュール手順にするように指示します。そうすれば、このナンセンスについて心配する必要はありません。)したがって、何かになってしまいます。このような:

MODULE psapi
USE psapi_types ! This is for the benefit of users of module psapi
INTERFACE
FUNCTION newroutine (arg)
USE psapi_types
INTEGER :: newroutine
TYPE (sometype) :: arg
...

Intel Visual Fortranを使用している人は、実際には、この目的のために、他のWin32APIのすべての型と定数を含む巨大なモジュールIFWINTYがあることを知っています。それは厄介でエレガントではありませんが、それはあなたがしなければならないことです。今まで...

Fortran 2003は、この残念な状況にいくらかの優雅さを取り戻そうとしますが、古いソースとの互換性を維持するために、インターフェイスブロックがホストアソシエーションに参加していることを宣言することはできません。代わりに、新しいステートメントIMPORTが作成されました。IMPORTは、インターフェースブロックにのみ表示でき、ホストスコープに表示される名前をインポートするようコンパイラーに指示します。

IMPORTは、USEステートメントの後、ただしインターフェース本体のIMPLICITステートメント(FUNCTIONまたはSUBROUTINE宣言)の前に配置されます。IMPORTには、USEと同様に、オプションのimport-name-listを含めることができます。1つがないと、ホストでアクセス可能なすべてのエンティティがインターフェイス本体内に表示されます。リストを使用すると、指定されたエンティティのみが表示されます。

IMPORTを使用すると、PSAPIモジュールは、次の変更を加えた最初の例のようになります。

...
FUNCTION newroutine (arg)
IMPORT
INTEGER :: newroutine
TYPE(sometype) :: arg
...

必要に応じて、次を使用できます。

IMPORT :: sometype

その1つの名前だけをインポートしたかったと言います。素晴らしく、きちんとしていて、すべてが1つのモジュールにあります!

「しかし、なぜあなたは私にこれを言っているのですか?」、「それはFortran 2003の機能であり、IntelFortranはまだFortran2003のすべてを実行しているわけではありません」とあなたは尋ねるかもしれません。確かにそうですが、F2003の機能をコンパイラーに追加し続けており、IMPORTは8月にそれを実現しました。したがって、合理的に最新の状態を維持している場合は、心ゆくまでインポートして、タイプと定数用の別のモジュールの混乱をなくすことができます。

他にどのようなF2003グッズが利用できるかを知りたい場合は、各アップデートのリリースノートを確認してください。サポートされているF2003機能の完全なリストは、各号にあります。全部集めろ!」

于 2014-01-08T14:20:52.433 に答える