|
|
|
|
|
Fでは,副プログラムの引数の授受属性をつけなくてはなりません.intent(inout)としておけばよいのですが,なるべくintent(in)とintent(out)にしようと心掛けることになります.しかし,intent(out)には落とし穴がありますので,注意が必要です.
次のモジュールでは要素が二つの派生型を定義し,それぞれの要素を変更するサブルーチンsetA, setBが用意されています.これらのルーチンの実引数の値をルーチンの中で使用しないことから,intent(out)と しました.これらをメインから呼ぶとサブルーチンで変更しない方の要素が初期値に戻ってしまいます.したがって誤りです. intent(out)とすると新しいオブジェクトが生成されるためだと思います.変更ではなくて,オブジェクトを生成し,片方だけに代入をしていることになっています.変更しない方も含めて,引数の前の値は必要なので,intent(inout)とすべきです. 誤ったintent(out)は,メモリリーク発生の原因となる可能性があります. module mod type, public :: mytype real :: a = 1.0 integer :: b = 2 end type mytype type(mytype), public, save :: z public :: setA, setB contains subroutine setA(x, y) type(mytype), intent(out) :: xreal, intent(in) :: y x % a = y print *, x end subroutine setA subroutine setB(x, y) type(mytype), intent(out) :: x integer, intent(in) :: y x % b = y print *, x end subroutine setB end module mod |
|
2002年04月17日 14時13分07秒
|
|
|
|
あたりまえのことですが,ときどき混乱するので,メモをしておきます.2 次元配列では,行は横に並んだ要素からなるベクトルで,記号は i,列は縦に並んだ要素からなるベクトルで,記号は j です.Fortran では,多次元配列での要素の並び方は,i, j, k, ... の内側から変化します.つまり,2 次元の場合は,列を固定して行が変化する順に要素が並んでいます. F/f90/f95 の配列の和をとる関数 sum() で次元 dim を指定すると,その次元以外を固定して指定した次元の要素について和をとります.2 次元配列 a で sum(a, 1) とするとそれぞれの列の和をとります.行の和でなく,行が縮約される(なくなる)ことになります. 例えば,3 次元配列 t に気温が格納されているとすると,気温の子午面分布は t_zonalmean = sum(t, 1) / i_max で計算できます.なお,t と同じ形状の logical 配列において,データが欠損しているところ(例えば,等圧面データで等圧面が山の中にあたる場合)を .false. として,sum に与えると欠損値を除いて和をとることができます. |
|
2001年09月18日 09時08分59秒
|
|
|
|
モジュールのサブルーチンへのアクセスをより細かく制限したいと思い,interface の階層化を試みましたが,これはできないようです.
module mod_a private :: sub_1, sub_2 interface sub_a module procedure sub_1, sub_2 end interface sub_a end module mod_a mod_b 内の sub_b も同様に定義し, mod_c にまとめます. module mod_c use mod_a, mod_b private interface sub module procedure sub_a, sub_b ! error end interface end module mod_c sub_1 を sub_a1 などとし, public にして mod_c で interface sub module procedure sub_a1, sub_a2, & sub_b1, sub_b2 end interface とすると動作しました. |
|
2001年08月16日 18時08分59秒
|
|
|
| f90/f95/F でオブジェクト指向プログラミングを実践する方法がここに紹介されています. ポインタを使って dynamic dispatching を実装したところが新しいようなのですが,可読性が落ちるように思います. 冗長になりますが,手続きの多重定義を使って一般的な手続きのインターフェースを宣言する方が分かりやすいように思います. |
|
2001年08月09日 19時16分57秒
|
|
|
|
F では protected などという参照属性はありません.use をくり返していったときに, public と指定した変数や手続きはどこまで参照可能なのでしょうか.
public と指定したものは,use 文で直接参照したプログラム単位でのみ参照できます.use で参照したモジュールが参照しているモジュールの中のものは参照できません. |
|
2001年08月09日 19時10分36秒
|
|
|
|
ユーザー定義型の要素の参照属性は private 文で行います.
type, public :: my_type integer, private :: i end type my_type はエラーで, type, public :: my_type private integer :: i end type my_type などと参照を禁止する要素を private 文の後に並べます. なお,private 文は type の参照属性が public のときにのみ有効です. |
|
2001年08月09日 19時07分00秒
|
|
|
|
-r8 オプションでデフォルトの実数を real*8 としたときに,real*4 を使うには,
integer, parameter :: single=4 real(kind=single) :: x として,-kind=byte オプションをつけてコンパイルします.今のプロセッサには real*8 が自然です.また,単精度では数値微分を取るとすぐに桁落ちするので,倍精度はよく使います.私は,-r8 と -kind=byte の組み合わせを常用することにしたいと思います. |
|
2001年06月18日 19時01分42秒
|
|
|
|
f90/f95/Fでは、精度をselected_real_kind()を使って指定することになっていますが、いちいち面倒です。Fには f90_kind というモジュールを使うか、自分なりに作っておくといいでしょう。また、バイナリファイルを読む場合のように、変数のサイズをバイトで指定したいこともあります。man F によると、-kind=byte というオプションを使えば、kind はバイトで指定できます。つまり、
interger, paramter :: double=8 real(kind=double) :: x とできます。kindは名前なし定数(数字そのまま)ではなく、名前付き定数でないとだめなので、注意が必要です。なお、-r8 というオプションを使うと、単に real と宣言したものが、すべて倍精度になります。 |
|
2001年05月29日 18時05分45秒
|
|
|
|
makeを使うときは、サフィックスルールに配慮が必要です。.modはModulaのソースとして認識されてしまうからです。
.SUFFIXES: .SUFFIXES: .f95 .o などとして既定値をクリアするとよいでしょう。 |
|
2001年05月29日 17時57分43秒
|
|
|
| 現行のFでは、メインプログラムの中にサブプログラム(サブルーチンや関数)が書けます。前のバージョンでは禁止されていたものです。内部サブプログラムの取り扱いは、モジュールと変わらないので、コンパイラは簡素化されたそうです。サブプログラムは、contains文に続いて記述します。モジュール内の内部サブプログラムは従来どおり禁止となっています(fortran.comのWaltさんによる)。 |
|
2001年05月23日 19時38分58秒
|
|
|
| Fからf77のサブルーチンを呼ぶことができます。このとき、interfaceは書かないようにします。interfaceがあれば、コンパイラに引き数の型をチェックさせることができます。しかし、配列の受け渡しのときに困ることになります。Fでinterfaceを書くと、assumed shapeになります。このとき、配列へのポインタ以外に配列のサイズなどのdescripterが渡されることになります。interfaceを介して余計な情報が渡されると、そんなものは知らないf77は予想外の動作をします(Fortran CompanyのWaltさんによる)。 |
|
2001年05月23日 19時33分46秒
|