東京工業大学大学院理工学研究科基礎物理学専攻中村研究室メンバー

ホームページおぼえがき > FORTRAN

FORTRAN

FORTRANのおぼえがき。主にg77(GNUのFORTRAN77コンパイラ)について書く。本おぼえがきによって、同じことを何度も調べるという愚行が排除されるでしょう。

(制作中。わからないところ多し。間違いが有る可能性大。実行してないコードが多々あり。)

FORTRANについて

長所
短所

コーディングのきまり

■ 大文字/小文字

FORTRANでは、大文字と小文字の区別はない。

■ コメント

コメントは、行の最初に c, !, * を書くか、行末に ! を書く。

c     ここはコメント
!     ここはコメント
      para = 1      ! ここもコメント

■ 行頭

行頭は6文字分のスペースを開ける。

      para = 1.0

行頭6文字以内に、整数を書くこともできる。プログラムの行数を書いたり、goto文用に使う。

101   para1 = 1.1
102   para2 = 1.2
103   para3 = 1.3
104   goto 105
c    ここは飛ばし
105   continue

■ 1行の文字数

1行は72文字以内に収める。72文字以上書いても無視される。

      x8901 = 5+7+9+1+3+5+7+9+1+3+5+7+9+1+3+5+7+9+1+3+5+7+9+1+3+5+7+9012

長い式などを書きたい場合は、複数行に分けて書く。2行目以降を継続行と呼び、行頭から6文字目に空白でもゼロでもない文字を書くと、継続行となる。

      x8901 = 5+7+9+1+3+5+7+9+ ! 最大72文字
     &789 +                    ! 継続行(最大72文字)
     & +901                    ! 継続行(最大72文字)
     + +901                    ! 継続行(最大72文字)

行頭6文字以内にタブ文字があると、その行はタブフォーマットと呼ばれる行になり、1行に255文字目までかける。

	para1=1     ! 最大255桁
101	para2=2     ! 最大255桁

宣言

■ 使用可能な変数名

変数名の頭文字はa〜zのアルファベットでなければならない。頭文字以外は、数字やアンダーバー(_)が使える。

      season        ! OK
      spring_8      ! OK
      autumn2winter ! OK
      _summer       ! NG
      4seasons      ! NG

変数名は割りと長くても大丈夫かも。100文字の変数名が使えた(タブフォーマットの行)。

■ 整数の宣言

2バイト整数、4バイト整数を宣言する。

      integer    para1    ! 4バイト整数を格納する変数para1の宣言
      integer*2  para2    ! 2バイト整数を格納する変数para2の宣言
      integer*4  para3    ! 4バイト整数を格納する変数para3の宣言

メモ) 2バイト整数は、-32768 〜 32767 (-215 〜 215-1) の65536個 (216個=16bits=2bytes) の整数が扱える。4バイト整数は、-2147483648〜2147483647 (-231〜231-1) の232個 (=32bits=4bytes) の整数が扱える。

■ 実数の宣言

4バイト実数、8バイト実数を宣言する。

      real    para1    ! 4バイト実数を格納する変数para1の宣言
      real*4  para2    ! 上と同義
      real*8  para3    ! 8バイト実数を格納する変数para3の宣言

メモ) 4バイト実数は、単精度実数、8バイト実数は倍精度実数とも言う。倍精度実数の方が、単精度実数よりも精度が倍?より正確な計算をしたいときは、倍精度を使う。

■ 配列の宣言

配列の添字は1から始まる。

      real*8 a(3) ! 8バイト実数型の配列 a(1),a(2),a(3)の宣言

添え字を0からにとか、-3からとかにしたい場合は、以下のように書く。

      real*8 b(0:3)  ! 配列 a(0),a(1),a(2),a(3)の宣言
      real*8 c(-3:1) ! 配列 a(-3),a(-2),a(-1),a(0),a(1)の宣言

配列の数の省略はできない。

      real*8 a(:)  ! コンパイルエラー
      real*8 a(3:) ! コンパイルエラー

多次元配列の宣言

      real*8 a(2,3)
c       以下の6個の配列宣言
c       a(1,1) a(1,2) a(1,3)
c       a(2,1) a(2,2) a(2,3)

      real*8 b(0:2, 1:3, -1:1)
c       以下の27個の配列宣言
c       b(0,1,-1) b(0,1,0)  b(0,1,1)
c       b(0,2,-1) b(0,2,0)  b(0,2,1)
c       b(0,3,-1) b(0,3,0)  b(0,3,1)
c
c       b(1,1,-1) b(1,1,0)  b(1,1,1)
c       b(1,2,-1) b(1,2,0)  b(1,2,1)
c       b(1,3,-1) b(1,3,0)  b(1,3,1)
c
c       b(2,1,-1) b(2,1,0)  b(2,1,1)
c       b(2,2,-1) b(2,2,0)  b(2,2,1)
c       b(2,3,-1) b(2,3,0)  b(2,3,1)

■ parameter文 + 配列の宣言

配列を宣言するとき、配列の長さは定数でなければならず、変数にすることはできない。

      implicit none
      integer m
      m=2             ! ここでエラー。宣言文の前に実行文が来てはいけない。
      real a(m)       ! これは、無理。parameter文を用いて同じようなことが出来る(下記参照)。

      a(1)=1.
      a(2)=2.
      write(*,*) a

      end

定数式を用いた配列の宣言。FORTRANのparameter文は、C言語のプリプロセッサ命令 #define に似た役割をする?

      implicit none
      integer m, n
      parameter(m=3, n=2)   ! 定数3, 2 にm, nという名前をつける。
      real a(m,n)           ! 配列a(3,2)の宣言

      a(1,1) = 1.
      a(2,1) = 2.
      a(3,1) = 3.
      a(1,2) = 4.
      a(2,2) = 5.
      a(3,2) = 6.

      write(*,*) a

      end

実行結果
  1.  2.  3.  4.  5.  6.

■ 文字列を格納する変数の宣言

      character*6 str1, str2       ! 6つの文字(1バイト文字が6個)を格納できる変数str1とstr2の宣言
      character str3*8, str4*10    ! 8文字を格納できる変数str3と10文字を格納できる変数str4の宣言

■ 関数の宣言

関数を使うときは、宣言しなければならない(ただし、implicit noneを書いたとき)。

      implicit none
      real f,x
      x=1.0
      write(*,*) f(x)
      end

      real function f(x)
        implicit none
        real x
        f = x+1
        return
      end

関数の引数の型は関数内での型宣言と同じでなければならない。よって、以下のコードはエラーとなる。

      implicit none
      real*8 f,x,y
      x=2.0d0                  ! 倍精度実数の2.0d0がxに代入される
      y=2.0                    ! 単精度実数の2.0が倍精度実数に型変換されてyに代入

      write(*,*) f(x)          ! ここは正しい
      write(*,*) f(y)          ! ここも正しい
      write(*,*) f(2.0d0)      ! ここも正しい
      write(*,*) f(2)          ! 整数型を引数としているため、ここでコンパイルエラーとなる
      write(*,*) f(2.0)        ! 単精度実数を引数としているため、ここもコンパイルエラーとなる
      write(*,*) f(float(2))   ! float()の戻り値は単精度実数であるため、ここもコンパイルエラーとなる

      end

      real*8 function f(x)
        implicit none
        real*8 x
        f = x+1
        return
      end

■ 暗黙の型宣言

宣言文を省略した場合、変数名の頭文字によって、その型が暗黙のうちに宣言される。これを暗黙の型宣言という。宣言のされ方は以下のとおり。

以下の2つのコードは同じ意味。

      integer*4  i
      real*4    para
      i = 3
      para = 4.0
      write(*,*) i, para
      end
      i = 3
      para = 4.0
      write(*,*) i, para
      end

■ 暗黙の型宣言を無効にする

コードの頭にimplicit noneと書く。

      implicit none
      integer*4  i
      real*4    para
      i = 3
      para = 4.0
      write(*,*) i, para
      end

■ implicit文を使う

変数名の頭文字によって型を決定したいときは、implicit文を使う。

      implicit integer(a-c,i,j)  ! 頭文字がa, b, c, i, jで始まる変数は整数型になる。
      implicit real*8(d-g,k)     ! 頭文字がd, e, f, g, kで始まる変数は実数型になる。
      aa = 1    ! 整数型変数 aa
      ii = 2    ! 整数型変数 ii
      dd = 1.0  ! 実数型変数 dd
      kk = 2.0  ! 実数型変数 kk
      mm = 2    ! 暗黙の型宣言に従い、mmは整数型変数      
      end

メモ) "inplicit none"と"implicit integer(a-c)"などは一緒に書けない。

代入

read(*,*), write(*,*)については後述

■ 数値の代入

倍精度で数値を代入するときは、最後にd0をつける。ただし、ファイルやキーボードからread(*,*)で読み込むときは、d0と書かなくても倍精度で読み込まれるらしい

      real*8 para1, para2
      para1 = 1.1                 ! 単精度の数値を代入
      para2 = 1.1d0               ! 倍精度の数値を代入

c  1.1d0 は 1.1*10^0という意味。
c  1.1d-1 とすれば、 1.1*10^-1という意味になり、1.1d-1≒0.11。

      write(*,*) "para1=", para1
      write(*,*) "para2=", para2

      read(*,*) para1	            ! キーボードで1.1と入力
      read(*,*) para2	            ! キーボードで1.1d0と入力
      write(*,*) "para1=", para1
      write(*,*) "para2=", para2
実行結果
 para1= 1.10000002
 para2= 1.1
 para1= 1.1
 para2= 1.1

■ 文字列の代入、表現

文字列は"〜"または、'〜'で表す。" 自身を表したいときは、'〜'の中で用いるか、\"とする。

	character*6 str1, str2

	str1 = "abcdef"
	str2 = 'ghi'
	write(*,*) "str1=" , str1, ' str2=', str2 

	str1 = 'tes"t"'
	str2 = "tes\'t\""
	write(*,*) "str1=" , str1, ' str2=', str2
	
	end
実行結果
 str1=abcdef str2=ghi
 str1=tes"t" str2=tes't"

標準入出力

■ write(*,*)の書式

write(*,*)の後ろにパラメータをカンマで区切って書く。

	para1 = 2.0d0
	para2 = 3.0d0
	write(*,*) "paras:", para1, para2
実行結果
 paras: 2. 3.

■ write(*,*)の改行

write(*,*)は表示の際、行末が改行される。則ち、C言語のように \n を書かなくても改行される。また、行の先頭にスペースが入る。

■ read(*,*)で読み込む行数がわからないとき

以下のように書くと、read(*,*)でデータが読み込まれなくなったとき(?)、文番号100にすすむ。

	do
		read(*,*,end=100) a, b, c
	enddo
100 	continue

ファイル入出力

■ ファイルのオープン/入力/出力

以下のファイルを読む。

ファイル名: input
99911.0 99912.0 99913.0
99921.0 99922.0 99924.0
99931.0 99932.0 99933.0

入力/出力プロラムは以下のとおり。

      real*8 a(3,3)

      open(10, file = "input")  	! ファイルをオープンし、ファイルハンドルっぽいもの10を取得
      read(10,*) a(1,1)
      read(10,*) a(2,1),a(2,2),a(2,3)
      read(10,*) (a(3,i), i=1,3)    ! a(2,1),a(2,2),a(2,3) ⇔ (a(3,i), i=1,3) ?  
c    ファイルはクローズしなくても良いかも?

      open(20, file = "output")
      write(20,*) a(1,1), a(1,2), a(1,3)
      write(20,*) a(2,1), a(2,2), a(2,3)
      write(20,*) (a(3,i), i=1,3)

	end

実行後、以下の内容のファイルができる(*にはなんか変な値が入る)。

ファイル名: output
  99911.     *       *
  99921.  99922.  99924.
  99931.  99932.  99933.

■ リダイレクションを用いたファイル入出力

上記プログラムは、シェルのリダイレクションを用いても実現できる。プラグラムを以下のように変更。

      real*8 a(3,3)

      read(*,*) a(1,1)
      read(*,*) a(2,1),a(2,2),a(2,3)
      read(*,*) (a(3,i), i=1,3)

      write(*,*) a(1,1), a(1,2), a(1,3)
      write(*,*) a(2,1), a(2,2), a(2,3)
      write(*,*) (a(3,i), i=1,3)

      end

したらば、シェルで以下を実行。

$ ./a.out < input > output

演算子

■ 関係演算子(比較演算子?)

g77において、関係演算子に<、>、<=、>=が使えない。gfortranとかは使えるかも?とりあえず、関係演算子は以下のとおり。

関係演算子
演算子意味
.gt. greater than ( > )
.ge. greater than / equal ( >= )
.lt. less than ( < )
.le. less than / equal ( <= )
.eq. equal ( == )
.ne. not equal ( != )

■ 論理演算子

論理演算子は以下のとおり。

論理演算子
演算子意味
.and. かつ (&)
.or. または (|)

使用法は以下の様。

      if (i .eq. 10 .and. j .ne. 10) then
        write(*,*) "i is eqaul to 10, and j is not equal to 10."
      endif

ループ処理

■ do文について

ループ処理はC言語のwhile,for,do文のようにバリエーションがなく、do文ひとつしかない(ただし、書式によって動作が変わる)。

■ do文書式

iを1から10まで1ずつ変化させる。

      do i = 1, 10
        write(*,*) "i=", i
      enddo

iを1から10まで2ずつ変化させる。

      do i = 1, 11, 2
        write(*,*) "i=", i
      enddo

ループを抜けるときは、goto文しかつかえないかも?

      i = 1
      do
        if (i .gt. 10) then
          goto 100
        endif
        write(*,*) "i=", i
        i = i + 1 
      enddo
100   continue

参考文献・webページ


ページ制作履歴
2007/10/18 制作開始
2007/12/09 変更
2008/01/15 宣言関係追加
2008/02/02 コーディング関係追加