Fortran Builder Logo
Fortran Builder




大学生協
今だけ!
Fortran Builder
+NAGライブラリ
大学生協限定
キャンペーン実施中!




Fortran Consulting Logo
Fortran
コンサルティング




NAG Library Image
NAG Fortran
ライブラリ
関連情報

ナビゲーション:前へ   上へ   次へ

18 知識として必要な過去のFortran

ここでは新しく書くプログラムでは必要ないものの、 既に世の中に存在する多くのFortranプログラム資産を理解する上で必要なFortranの機能について説明をします。

18.1 固定形式

固定形式はパンチカードによってプログラムを入力していた時代の産物ですので、 新しくプログラムを作成する場合の使用は推奨されません。しかしながら 過去に作成されたプログラムを理解したり、あるいはメンテナンスしていく上で ある程度の知識が必要とされますので、以下の要点を説明します。
  • 1行あたり72カラムまでの制限がある。
  • 1カラム目から5カラム目には文番号を記述できる。 特に1カラム目に'C'や'*'などの数字以外が記述されている場合には その行がコメント行として解釈される。
  • 6カラム目は通常は空白にする。空白でない場合(何か文字を指定した場合には)前の行からの継続行とみなされる。
  • 7-72カラム目にプログラム文を記述する。
  • 文字定数表現以外の空白は意味がないので、例えばWRITEも W R ITEも同様に扱われる。 同様にINTEGERABCとしてもINTEGER ABCと同じ意味となる。


[ fixed.f ] - 固定形式のサンプル
      PROGRAM MAIN
C  以下の行のようにキーワード(CHARACTER)の後の空白はいらない
      CHARACTERMYNAME*20
C この行はコメント
      WRITE (*,*) "Please enter your name:"
C  下記は2行にわたって記述する例(継続行の例)
      READ (*,*)
     &MYNAME
C  下記は空白が読み飛ばされる例
      WR I TE (*,*) "Name Entered was:", MYNAME
      END

出力例:
 Please enter your name:
Taro
 Name Entered was:Taro

18.2 共有(COMMON)ブロック

共有ブロックはプログラム単位間でデータのやり取りをする場合などに利用可能な 機能ですが、探し出しにくいバグの原因となるので、その利用は推奨されていませんが 過去のプログラムに多くみられますので、ここで概要を説明します。

18.2.1 共有ブロックの利用方法

共有ブロックは以下のようにCOMMON文を用いて利用します。
  COMMON [/ブロック名/]変数並び

同じブロック名は同じデータ領域を意味します。又ブロック名を指定しない場合は特別な共有ブロックで 無名共有ブロックと呼ばれます。

共有ブロックは例えば以下のように利用しデータの共有が可能となります。

[ common.f90 ] - COMMONブロックのサンプル

subroutine mysub
  common /mydata/x,y,z   ! mydataという共有ブロックを指定
  x = 99
  y = y + 1.0
end subroutine

program common
  common /mydata/x,y,z   ! ここでもmydataという共有ブロックを指定
  x = 5.0
  y = 10.0
  z = 15.0
  print *, "x =", x, "y =", y, "z =", z
  call mysub
  print *, "x =", x, "y =", y, "z =", z
end program common

出力例:
 x =   5.0000000 y =  10.0000000 z =  15.0000000
 x =  99.0000000 y =  11.0000000 z =  15.0000000

18.2.2 共有ブロックの初期化方法

共有ブロック(無名共有ブロックを除く)はdata文により初期化することができます。 その場合に初期値設定プログラム単位内にその記述を行わなければなりません。 初期値設定プログラム単位は以下のように書式の通り記述します。
block data [初期値設定プログラム名]
  [単純宣言文]...
end [block data [初期値設定プログラム名]]

例)
block data
  common /mydata/ i,j
  data i,j/10,20/
end block data

以下に共有ブロックの初期化を行うサンプルを示します。

[ common-init.f90 ] - COMMONブロックの初期化を行うサンプル

program common_init
  implicit none
  integer a(4), b
  common /mydata/ a,b
  print *, "a =", a, "b =", b
  call mysub
  print *, "a =", a, "b =", b
end program

subroutine mysub
  implicit none
  integer a(4), b
  common /mydata/ a,b
  a = a + b
end subroutine

block data
  implicit none
  integer a(4), b
  common /mydata/ a,b
  data a/1,2,3,4/, b/100/
end block data

出力例:
 a = 1 2 3 4 b = 100
 a = 101 102 103 104 b = 100

18.3 暗黙の型宣言

Fortranでは変数の宣言が必須ではありません。 プログラムの保守性の観点から、 本テキストでは常に変数の宣言を必須とする implicit none の利用を強く推奨しています。 しかしながら世の中に存在する多くのFortranプログラムは、 変数の宣言を行わずに変数を利用するやり方(implicit noneを指定しない記述方法)が使われていますので、 ここで説明します。

18.3.1 implicit文を全く使わない暗黙の型宣言ルール

Fortranではimplicit文を指定しない場合に変数名の最初の文字により変数の型が決定されます。 これを暗黙の型宣言と呼びます。

暗黙の型宣言は以下のルールに基づきます。 a-h,o-zで始まる変数は基本実数型となる
i-nで始まる変数は基本整数型となる
以下に例を示します。

[ implicit.f90 ] - 暗黙の型宣言を用いるサンプル

program implicit
  a = 100   ! 基本実数型
  i = 100   ! 基本整数型
  print *, "a =", a
  print *, "i =", i
end program implicit

出力例:
 a =   1.0000000E+02
 i = 100

18.3.2 implicit文によって任意の型をマッピングする

過去のプログラムには以下のようにimplicit文を用いて、 任意の英文字ではじまる変数の型を決定する方法も多く見うけられます。
  implicit 型 (英字範囲並び), [,型 (英字範囲並び)]...

すべての実数変数を倍精度として扱いたいような場合に例えば以下のような記述が可能です。

  implicit real*8(a-h,o-z)   ! aからh、oからzではじまる変数の型をreal*8として扱う

18.4 DOループの古い書き方

過去のプログラムにおいてDOループは文番号を指定する以下のような書式が最も一般的でした。 (新しいプログラムでは文番号を伴わないDO〜END DOが推奨されています)
DO 文番号 変数=初期値, 最終値 [,刻み幅]
  繰り返したい処理
文番号 CONTINUE

ここでcontinue文は特に何もしません。(「場所取り」の役割を果たしています)

例)
    do 20 i=1, n
      do 10 j=2, m
        a(i,j) = i*m
 10   continue
 20 continue

2重ループを1つのcontinueで共有することも可能で、以下のような記述もよく見られます。
以下は上記と同じ動作する例です。
    do 10 i=1, n
      do 10 j=2, m
        a(i,j) = i*m
 10 continue

18.5 GOTO文

過去のプログラムではGOTO文が多用されている傾向にあります。 GOTO文は文番号が指定する場所へ処理を移行させる記述方法です。
GOTO 文番号
もしくは
GO TO 文番号

例)
     if ( stat .ne. 0) goto 10
     ...
  10 print *

GOTOには実はもう一つの書き方(計算形)があります。 計算形GOTOはFortranにおいて廃止事項ですが古いプログラムで見うけられる記述方法ですので ここで説明します。計算形GOTOは与えられた式(整数)の値により、 その位置に記述された文番号へジャンプします。

GOTO (文番号並び) [,] 整数式

例)
   index = 3
   go to (10,20,30) index - 1 ! 2番目の文番号=20へジャンプ
   stop
10 print *, 'LABEL:10'
   stop
20 print *, 'LABEL:20'
   stop
30 print *, 'LABEL:30'
   stop
   end

18.6 大きさ引継ぎ配列

サブルーチンや関数で配列を引数として受け取る際に仮引数の最終次元の大きさ指定を*(アスタリスク)とする記述方法があります。 これは配列の寸法を実引数から引き継ぐことを意味する記述で大きさ引継ぎ配列と呼ばれます。 新しく書くプログラムではより安全で便利な形状引継ぎ配列を利用することを推奨します。

以下に大きさ引継ぎ配列の例を示します。

program assumed_size
  implicit none
  integer :: a(2) = (/1,2/)
  integer :: b(3,2) = reshape( (/1,2,3,4,5,6/), (/3,2/) )
  call mysub(a,b)
contains
  subroutine mysub(a,b)
    integer a(*), b(3,*)
    ! このサブルーチン内でaの大きさやbの大きさを知るすべが無い
    ! 例えば print *, a や b(1,:) 等とはできない
    print *, a(1), a(2)      ! このように指定することは可能
    print *, b(1,1), b(1,2)  ! このように指定することは可能
  end subroutine
end program

出力例:
 1 2
 1 4

以下に比較の対象として新しい書き方である形状引継ぎ配列の例を示します。

program assumed_shape
  implicit none
  integer :: a(2) = (/1,2/)
  integer :: b(3,2) = reshape( (/1,2,3,4,5,6/), (/3,2/) )
  call mysub(a,b)
contains
  subroutine mysub(a,b)
    integer a(:), b(:,:)     ! このようにコロンを記述する事で形状引継ぎとなる
    print *, a               ! 配列の形状が配列と共に渡ってきているのでこのような記述もOK
    print *, b(1,:)          ! 部分配列もOK
    print *, "aの各次元の大きさ =", shape(a)   ! 配列の形状がちゃんと取得できる
    print *, "bの各次元の大きさ =", shape(b)   ! 配列の形状がちゃんと取得できる
  end subroutine
end program

出力例:
 1 2
 1 4
 aの各次元の大きさ = 2
 bの各次元の大きさ = 3 2

18.7 算術IF文

古い書き方に算術IFというものがあります。 この書き方はFortranでは廃止予定機能ですが古いプログラムには見かけられる書き方です。

算術IF文は、与えた式が0より小さい場合に最初の文番号へ、 0の場合は2番目の文番号へ、 0よりも大きい場合には3番目の文番号にジャンプします。

if ( 式 ) 文番号1, 文番号2, 文番号3

例)
i = -1
if (i) 100, 200, 300   ! 100へジャンプします

18.8 入出力時、及びDATA文においてのDO形反復

過去のプログラムでは入出力時やDATA文において配列成分を順番に指定したい場合に DO形反復が多用されています。この書き方は特に悪いものではありませんが、 新しいプログラムにおいてはよりわかりやすい配列全体を指定する方法や部分配列が推奨されています。

以下にDO形反復を用いて配列の入出力を行っている例を示します。

  integer,dimension(3,2) :: a, b
  ...
  write (10,*) ((a(i,j),i=1,3),j=1,2)    ! DO形反復を用いて配列を全体書き出す例
  write (10,*) a                         ! 配列全体を指定。現在はこの書き方が推奨されています
  ...
  read (11,*) ((b(i,j),i=1,3),j=1,2)    ! DO形反復を用いて配列(全体)を読み込む例
  read (11,*) b                         ! 配列全体を指定。現在はこの書き方が推奨されています

18.9 PARAMETER文とDIMENSION文

PARAMETER文とDIMENSION文は過去のプログラムに多く利用されていますが、 新しいプログラムでは推奨されない書き方です。 (代わりに変数宣言時に属性としてこれらを指定することが推奨されています。)

18.9.1 PARAMETER文

PARAMETER文は名前付き定数を指定する際に使われますが以下のような書式を持ちます。
parameter( 定数名=初期値式 [,定数名=初期値式]... )

例)
【古いやり方】 - PARAMETER文による指定方法
integer Red, Green, Blue              ! この宣言が無い場合は暗黙の型宣言に基づく型となる
PARAMETER( Red=1, Green=2, Blue=3 )

【より良いやり方】 - PARAMETER属性を指定する方法
integer,parameter :: Red=1, Green=2, Blue=3

18.9.2 DIMENSION文

DIMENSION文は配列の宣言を行うもので、古いプログラムでよく見られる書き方です。 以下のような書式を持ちます。
dimension [::] 配列名(配列指定) [,配列名(配列指定)]... )

例)
【古いやり方】 - DIMENSION文による指定
integer a, b              ! この宣言が無い場合は暗黙の型宣言に基づく型となる
dimension a(10), b(4,3)

【より良いやり方(1)】 - 変数の宣言時に指定する
integer a(10), b(4,3)

【より良いやり方(2)】 - 変数の宣言時にdimension属性を指定する
integer,dimension(10) :: a
integer,dimension(4,3) :: b

18.10 EXTERNAL文

古いプログラムではEXTERNAL文が外部関数や外部サブルーチンを利用したい場合や引数として関数を渡したい場合などに利用されています。

External文は以下の形式を持ちます。

external 外部名並び

external文は実行部より前の宣言部(use文やimplicit文がある場合はそれらより後ろ)に記述します。

external文により宣言された外部手続名と組込み手続等の名前が重なる場合にはその名前を持つ組込み手続等は使用不可となり外部手続が優先されます。

EXTERNAL文では手続が外部手続である事を宣言するに過ぎず引数の型等の情報は含まれません。 そのため新しく作成するプログラムではEXTERNAL文の代わりに引用仕様(INTERFACE)を用いることが推奨されています。 引用仕様を用いることにより引数の型も含めた形での宣言が行えます。

尚、手続はEXTERNAL文で宣言することもしくは引用仕様を与えることが許されていますが、 両方を指定することは許されていません。

以下の外部サブルーチンを利用したい場合の例

! 単精度実数 a + b を表示する
subroutine add_and_print(a, b)
    real a, b
    print *, a + b
end subroutine add_and_print

【External文を利用する例 - 誤った引数の型であってもエラーとならない】
program external_example
  implicit none
  external add_and_print
  integer :: a=1, b=2
  call add_and_print(a,b)
end program external_example

出力例:
   4.2038954E-45    ← 引数の型の整合性が取れていなかったのでおかしな結果となってしまった

【引用仕様を利用する例 - より良いやり方=誤った引数の型でエラーを検出してくれる】
program interface_example
  implicit none
  interface
    subroutine add_and_print(a,b)
      real a, b
    end subroutine
  end interface
  integer :: a=1, b=2
  call add_and_print(a,b)  ! エラー 「誤ったデータ型INTEGER(正しくはREAL)が指定されました」等となる
end program interface_example

18.11 文関数

文関数は同じプログラム単位内で同じ計算を複数箇所で行いたいような場合に利用されます。 例えば y = 2 + 5x + 6x2 を複数箇所で計算させたいような場合以下のように記述します。
  myexpr(x) = 2. + 5.*x + 6.*x*x
  ...
  print *, myexpr(1.)     ! 2+5*1+6*1*1 = 13
  print *, myexpr(2.)     ! 2+5*2+6*2*2 = 22

文関数は新しいプログラムでは推奨されません。新しいプログラムでは内部関数の利用が推奨されています。 文関数を利用するプログラムコードと内部関数を利用するプログラムコードを示します。

【文関数を用いる例 - 現在は推奨されません】
program stmt_func
  implicit none
  real x, myexpr
  myexpr(x) = 2. + 5.*x + 6.*x*x    ! 文関数の定義
  print *, myexpr(1.), myexpr(2.)   ! 文関数の利用
end program stmt_func


【内部関数を用いる例 - 推奨される書き方】
program internal_func
  implicit none
  print *, myexpr(1.), myexpr(2.)   ! 内部関数の利用
contains
  function myexpr(x)                ! 内部関数の定義
    real x, myexpr
    myexpr = 2. + 5.*x + 6.*x*x
  end function myexpr
end program internal_func


出力例:
  13.0000000  36.0000000

18.12 その他の廃止事項等

上記以外で過去に許されていた形式で現在は廃止もしくは非推奨となっている機能の主なものを以下に示します。 (※あらたに書くコードには必要ありません)
  • ASSIGN文
  • 割当て形 GO TO 文
  • 割当て形 FORMAT文
  • ホレリス(H形編集記述子)
  • PAUSE 文
  • 実数型DO制御変数
  • IFブロック外からENDIFへのジャンプ
  • EQUIVALENCE文
  • ENTRY文



ナビゲーション:前へ   上へ   次へ

Results matter. Trust NAG.
Privacy Policy | Trademarks