「ユーザに二つの西暦年号を入力させ,その間の日数を計算する(両端の年を含む)」という課題を考える.計算の中核部分は,次のようになるであろう:
! ! year_start : 始まりの年 ! year_end : 終わりの年 ! answer=0 do year = year_start, year_end !...... ! !ここで西暦"year"年の日数を計算して,daysに入れる ! answer = answer + days end do ! ! ここで,答えはanswerに入っている !
さて,「西暦"year"年の日数を計算して,daysに入れる」のところには,もちろん第三章でとり上げたようなアルゴリズムを使えばよい.
よいのだが,それでは,「ある年の日数を計算する」必要が,プログラムのほかの場所でも生じたらどうなるだろうか? 各場所で何回も例のIF文を書くか?
それは無駄というものである.一つの機能を持つプログラムのパーツは一回書けばそれでよい. これを実現するのがサブルーチン(後述)と関数(function)である.
つまり,「一つの西暦年数値を与えるとその年の日数を返してくれる」プログラムのパーツ(つまり関数)を作っておいて,必要があればそれを呼び出せばよいのである.
では使い方をみてみる.
関数は,何か値を与えられたときに(現在時刻を返す関数など,稀に全く値を与えられない関数もある),一つの値を返す.そのため,その返す値の型を最初に宣言する(integer function
の部分).その宣言の後に関数の名前(days_of_year
),そして次のカッコの中に,受け取る値(year
)を,複数あるときはコンマで区切って書く. 関数ブロックはこのfunction文
から,end function文までである.
この,受け取る値のことを引数(ひきすう)という.
引数も変数だから,型宣言をしなければならない.それは普通の変数宣言と同じ.ただし,より一層引数の性格を明確にするためにintent属性をつけておくとよい.intent(IN)
は,関数が一方的に受け取るのみの引数であり,この関数の中では一切改変されない引数であることを表す.
intent(IN)
がついた引数を改変しようとするとコンパイル時にエラーがでる.
関数の戻り値は,関数を同じ名前(days_of_year
)を持つ変数が仮にあると考えて,その「変数」に普通に代入すればよい.この代入を行わなかったとき,関数の値がどうなるかは保証されない.
関数の呼び出し(call)はどうなるか.すでに紹介したMOD(n,m)
のように,ごく普通にdays_of_year(n)
のように書けばそれ自体が関数の答え(値)となる.
ただし,一つ注意点.implicit none
をつけている場合,使うユーザ定義関数も型宣言をする必要がある(integer :: days_of_year
).そうしないとコンパイルエラーとなる.
intent
属性も,関数も宣言が必要なことも,一見するとわずらわしいように思えるが,大規模なプログラム開発に当たっては予期せぬエラーを未然に防ぐ強力な武器となる.
↑の節ではユーザが定義する関数を紹介したが,FORTRANには最初から組み込まれている関数組み込み関数もたくさんある. このような関数を使うときには,型宣言は不要である.
よく使われる関数を紹介する.主に数学関数と文字列関数である.全ての関数を知りたければ,例えばリファレンス参照.
実数型:名前 | 意味 |
---|---|
SQRT(x) | 平方根 |
ABS(x) |
絶対値 |
SIN(x), COS(x), TAN(x) |
おなじみの三角関数 |
ASIN(x), ACOS(x), ATAN(x) |
逆三角関数 |
EXP(x), LOG(x), LOG10(x) |
指数関数と対数関数(自然・常用) |
SINH(x), COSH(x), TANH(x) |
双曲関数 |
|
|
AINT(x), ANINT(x) |
小数点以下切り捨て,四捨五入 |
REAL(i) |
整数iを実数にする |
MOD(i1,i2) |
剰余(i1をi2で割ったあまり) |
---|---|
INT(x), NINT(x) |
小数点以下切り捨て,四捨五入 |
MAX(a1,a2,...,an) |
最大値 |
---|---|
MIN(a1,a2,...,an) |
最小値 |
名前 | 意味 | 返す型 |
---|---|---|
ADJUSTL(s), ADJUSTR(s) |
右詰め・左詰め | 文字列型 |
CHAR(i) |
文字コードiに対応する文字 | integer |
ICHAR(s) |
文字sの文字コード | 文字型 |
INDEX(s1,s2) |
文字列s1の中で文字列s2を探し,最初に現れた先頭位置を返す(なければ0) | integer |
LEN_TRIM(s), LEN(s) |
文字列の,予約されている長さ・実際の(右の空白を除いた)長さ | integer |
LGE(s1,s2), LGT(s1,s2), LLE(s1,s2), LLT(s1,s2) |
文字列s1とs2を比較する.「辞書順」の大小(前後)関係. | logical |
REPEAT(s,n) |
文字列sをn回コピーした文字列 | 文字列型 |
SCAN(s1,s2[,BACK]) |
文字列s1の中から,文字列s2に含まれる文字を探し,もしあればその位置を返す.なければ0.BACKを.TRUE.(LOGICAL型の「真」を表す値)にすると,後ろから探す. | integer |
VERIFY(s1,s2[,BACK]) |
SCANの逆で,s1の中からs2に含まれない文字を探し,その位置を返す.BACKの意味も同じ. | integer |
TRIM(s) |
文字列sの,右側の空白を消去した文字列を作る | 文字列型 |