4. データの型 目次へ 4.1. 実数型と整数型 4.1.1. 基本的な型宣言 4.1.2. 暗黙の型宣言 4.1.3. 型の変換 4.2. 文字型と論理型 4.3. 定数名(PARAMETER) 4.4. 複素数型および高精度型 4.4.1. 複素数 4.4.2. 高精度実数 4.4.3. 精度の桁数指定 [90] 4.5. 異なる型の混合演算および代入 4.6. 変数の種別と属性 [90] プログラムで用いる全ての変数は,それがどの種のデータを表すかによって型をもっ ており,一般にその使用を予め宣言(予約)しておかなければならない。FORTRANには 伝統的な「暗黙の宣言」と呼ばれる,明示的に宣言を行わずにすむ方法がある。しかし ながら,特に数値データの型による処理の違いを正確に理解し,無用な混乱や誤りを 防ぐためには,全ての変数の型を宣言するように心がける方がよい。 4.1. 実数型と整数型 4.1.1. 基本的な型宣言 REAL :: 変数名のリスト [90] REAL 変数名のリスト INTEGER :: 変数名のリスト [90] INTEGER 変数名のリスト 宣言された変数は,それぞれ標準の4バイト実数(小数点をもつ数),4バイト整数 を表す。注:数値型のデフォルト精度や用意されている種類は,処理系によって異なる。 (初期値の設定) 型宣言文で変数に初期値を設定することができる。 例 INTEGER :: mask = 2147483647, k = 5**11 ← 算術式も可 [90] INTEGER mask/2147483647/, k/48828125/ ← / /で囲む。 式は不可 DATA文の方法: REAL x, y, z INTEGER :: mask DATA x/1.0/, y/2.0/, z/3.0/, mask/2147483647/ 4.1.2. 暗黙の型宣言 いずれの宣言も行われない変数は,次の規則にしたがう: 先頭が i,j,k,l,m,n で始まる変数=4バイト整数 それ以外の英字で始まる変数 =4バイト実数 (暗黙の型宣言の変更) 先頭文字の範囲指定 IMPLICIT 型(先頭文字または範囲) 例 IMPLICIT INTEGER(a-f,z) a,b,c,d,e,f,z で始まる変数を整数型 とする。 暗黙の宣言の無効化 IMPLICIT NONE [90] これにより,すべての変数は宣言せずに使うとコンパイルエラーとなり,つまらない プログラムミスが発見されやすくなる。 例 IMPLICIT NONE REAL :: x0, y0 x0 = 0.1 y0 = 2.0*xO ← x0(ゼロ)を xO(オー)と書いてしまった! 暗黙の宣言を無効にしないときには,変数xOは変数名の約束にかなっているので有効 であり,xO は内容が未定義の状態で引用されるため,コンパイル時には「未定義」と いうWarningが出るが,画面が流れてコンパイルが敢行されてしまうため,気がつかな いことが多い。普通は宣言時に xO=0.0 とみなされるため,知らぬ間に y0=0.0 となっ て計算が進行する。 4.1.3. 型の変換 データの型を変換するには,組込み関数 REAL(i) 整数iの値を実数化 INT(x) 実数xの値を整数化 を用いるか,あとで述べる代入文における型変換規則による。(→ 4.5.) 例題 4_1 「1年は約365.2422日である。これを日,時,分,秒になおせ。 (参考:365.2422 = 365 + 1/4 - 1/100 + 1/400... より,例題 3_3 の 「うるう年」のルールとなる。 )」[ex4_1.f90] ! --- Solar year --- REAL year, day, jikan,hun, byo INTEGER d, h, m year = 365.2422 day = AINT(year); d = INT(day) jikan = 24.0*(year - day); h = INT(jikan) hun = 60.0*(jikan - AINT(jikan)); m = INT(hun) byo = 60.0*(hun - AINT(hun)) PRINT*, '1年は', d, '日', h, '時間', m, '分', byo, '秒' END
このプログラムは,異なる型の混合演算・代入規則を用いれば,もっと簡単に書ける。 4.2. 文字型と論理型 文字データを表す変数は,すべて型および長さの宣言をしなければならない。 CHARACTER(LEN=長さ) :: 変数のリスト [90] CHARACTER :: 変数*長さ,... [90] CHARACTER*長さ 変数,...,変数*長さ CHARACTER 変数*長さ,... 「長さ」は文字数(バイト数)を表す整数値であり,二重に指定した場合は変数に 指定した長さが優先される。日本語文字では1文字が2バイトである。ただし,シス テムによっては前後に日本語コードの開始・終了を表す制御文字各2バイトを含むた め,n文字の日本語の長さ=2n+4 としなければならない場合がある。 論理データ(真と偽)を表す変数は LOGICAL :: 変数名のリスト [90] LOGICAL 変数名のリスト 4.3. 定数名(PARAMETER) 型宣言文で設定する初期値や上の文字型宣言の「長さ」,6章で扱う配列宣言におけ る配列の大きさなどは,一般に変数ではなく定数で与えなければならない。宣言文にお いてPARAMETER属性指定またはPARAMETER文を用いて定数(パラメータ)に英字名を付け ることにより,このような定数を書くべき場所に使うことができる。 型, PARAMETER :: 定数名=定数,... [90] PARAMETER(定数名=定数,...) 後者(PARAMETER文)の場合,用いる定数名は暗黙の宣言に従う外は,予め型宣言を しておかなければならない。 例 INTEGER, PARAMETER :: mask = 2147483647 REAL, PARAMETER :: pi = 3.141593, pi2 = 2.0*pi**2 CHARACTER(LEN=1), PARAMETER :: SP = " " 注)定数宣言された定数名は,プログラム実行中に代入文などによって値を変える ことはできない。 4.4. 複素数型および高精度型 4.4.1. 複素数 COMPLEX :: 変数のリスト [90] COMPLEX 変数のリスト 実部,虚部が4バイト実数から成る複素数を表すことになる。 例題 4_2 「実数xと整数nを読み込んで,複素数 z = exp(ix) を作り,z**n と(COS(nx),SIN(nx)) を比較せよ。」[ex4_2.f90] ! --- Complex number --- REAL :: x COMPLEX :: z INTEGER :: n COMPLEX, PARAMETER :: i = (0.0, 1.0) ! PRINT *,' Input a real number x and an integer n:' READ*, x, n; z = EXP(i*x) PRINT*, z**n PRINT*, COS(n*x), SIN(n*x) END
4.4.2. 高精度実数 4バイト実数(単精度)では有効数字がおよそ7桁であり,高精度の計算を要する 場合には倍精度(8バイトで有効数字は約15桁),4倍精度(16バイトで有効数字は 約30桁)実数を用いる。ただし,4倍精度は必ずしも用意されているとは限らない。 REAL(8) :: 変数名のリスト [90] REAL*8 変数名のリスト DOUBLE PRECISION 変数名のリスト REAL*16 変数名のリスト 例題 4_3 「角度(度)を与えて,倍精度の三角関数 SIN, COS の値を求める。」[ex4_3.f90] ! --- Double precision --- REAL(8) :: deg, rad, s, c REAL(8), PARAMETER :: pi = 3.141592653589793_8 PRINT*,'Input angle variable in degree:' READ*, deg; rad = pi*deg/180.0_8 s = SIN(rad); c = COS(rad) PRINT*, 'SIN=', s, ', COS=', c PRINT*, 'COS^2+SIN^2=', s**2+c**2 END
倍精度(8バイト)の実数定数は,定数値_8 で与える。 4.4.3. 精度の桁数指定 [90] システムによって実数データのビット表現が異なることにより,必ずしも期待される 精度は共通にはならない。これを回避するために,[90]では欲する精度から必要な長さ (バイト数)を求める精度決定関数が用意され,これを用いて精度を指定する方法が設 けられた。 例 10進数で有効数字10桁の計算がしたい: INTEGER, PARAMETER:: p = SELECTED_REAL_KIND(10) REAL(KIND=p) :: r, s s = 3.14159265358979_p * r**2 これにより,実数変数 s,r は少なくとも有効数字10桁の精度が自動的に保証される。 普通のシステムでは,実際にはs,rにはシステムで用意された倍精度実数(p=8)が割り 当てられる。SELECTED_REAL_KIND関数によって変数sに割り当てられた精度を知るには 組込み関数 PRECISION(s) : 10進有効桁数が与えられる 組込み関数 KIND(s) : バイト数(=p)が与えられる を用いる。同様にして,整数の精度は整数精度決定関数 SELECTED_INT_KIND(望みの10進桁数) で与える。 注)ここでいう実数の精度は,単一データの有限長ビット表現で保証される精度であ って,いくつかのデータ間の計算結果の精度が同じように保証されるとは限らな い。アルゴリズムによっては信じられないほど精度が落ちることがある。 (例 極端に大きさの違う数値の間の加減算→桁落ち」) 4.5. 異なる型の混合演算および代入 異なる型の数値データの間の2項演算では,実数の整数ベキ演算を除いて,次の順位 によって,個々の演算において,別表の変換規則に基づき「強い方に変換して型を揃え て」から,演算が行われる。ただし,実数の整数ベキ演算「x**n」だけは文字通りに, 「xをn回かける」と解釈される。組込み関数では,単精度実数の代わりに複素数または 倍精度実数を書いた場合,自動的に関数値が複素数または倍精度となる(注1)。 整数<実数<複素数, 単精度<倍精度<4倍精度 例 COMPLEX(4) は REAL(8) より強い。 代入文・入力文 においては,別表に基づき代入先・入力先の変数の型に型変換して から,代入が行われる。 ============================================================================== 表 数値データの変換規則 --------------------------------------------------------------------------- 変換先 →| | | | 変換元 ↓ | INTEGER(4) | REAL(4) | REAL(8) | COMPLEX(4) --------------------------------------------------------------------------- INTEGER(4) | − | 小数点をつける | 実数化後,下位 | 実数化後, | | | に0を補填 | 実数部へ代入 --------------------------------------------------------------------------- REAL(4) | 切り捨てで | − | 下位に0を補填 | 実数部へ代入 | 整数化(INT) | | | 虚数部=0 --------------------------------------------------------------------------- REAL(8) | 切り捨てで | 下位を切り捨て | − | 単精度化後, | 整数化(INT) | | | 実数部へ代入 --------------------------------------------------------------------------- COMPLEX(4) | 実数部を採用 | 実数部を採用 | 実数部を採用し | − | して整数化 | | 下位に0を補填 | ============================================================================== もちろん,同じ型の数値データの間の演算結果の型は,元のデータの型と同じである。 最も誤りやすいのは 整数/整数 は 整数 である。 例えば,1/3 は 0, 7/3 は 2 となる。 例 REAL :: x x = 1/3 1/3(=0)の整数計算をしてから実数化 x = 1.0/3 1.0/3.0 としてから実数計算 x = 3.1416*(1/4)**2 1/4 が0となるので x=0.0 REAL(KIND=8):: x x = 1.0/3.0 単精度計算をしてから倍精度データに変換して代入 x = 1.0_8/3.0 3.0を倍精度に変換してから倍精度計算(注2) 注1)組込み関数の場合,実数引数が予定されている場所に整数を書く,(あるいは その逆)と誤りとなる。(例:2の平方根は,SQRT(2)ではなく SQRT(2.0) と 書かなくてはならない。) 注2)単精度の実数 0.1 を倍精度に変換するとき,単精度の有効桁のうしろに0が 補充されるだけであって,倍精度実数 0.1_8 とは異なる。(0.1 は2進数で は無限小数である。) 例題 4_4「西暦n年12月31日は,西暦元年(1年)1月1日(=月曜日)から 数えて何日目か?(例題 3_3 参照)」[ex4_4.f90] ! --- Calendar --- INTEGER:: n, s PRINT*, 'Input a year:' READ*, n s = 365*n + n/4 - n/100 + n/400 PRINT*, n, "年12月31日は,1年1月1日から数えて", s, "日目です。" END
4.6. 変数の種別と属性 [90] 型宣言文の完全な形は以下のようになる。 型宣言子[(LEN=長さ,KIND=種別指定)], 属性指定 :: 変数名のリスト 「長さ」は文字データの場合,種別は数値データの場合である。属性指定により,宣言 された変数がプログラムでどのように用いられるかの属性を定めることができる。上の PARAMETER はその例であるが,この他に,DIMENSION(配列属性),INTENT(引数の入出 力特性),POINTER,TARGET,SAVE,INTRINSIC,EXTERNAL,ALLOCATABLE,IMPLICIT な どがある。 ⇒4章先頭へ ⇒5章へ