IT pass HikiWiki - [itbase2017]Fortran 実習 変数 Diff

  • Added parts are displayed like this.
  • Deleted parts are displayed like this.

= 変数

Fortran に限らず, コンピュータ言語では「変数」を使って,
様々な処理を行います.
例えば, 数値や文字列を変数に入れることで, 予め決めた数字に限らずに
様々な数値に対して同じ計算を行うことができるでしょう.

しかし, プログラムで変数を使うためには, 使う前に「宣言」する必要が
あります.
この宣言は, 必ず, 計算や画面への出力などの実行文の前に行わなければなりません.

変数の宣言を体験してみましょう.
下のようなプログラムを variable.f90 というファイル名で作成しましょう.

  program variable

    implicit none

    num = 3
    val = 5

    print *, num, val
    print *, "num * val = ", num * val

  end program variable

このプログラムを作るには, 下のように入力して emacs を起動して,

  $ emacs variable.f90 &

上のプログラムの内容を打ち込みます.

簡単にプログラムを説明しておきます.

  implicit none

は, ここでは「おまじない」と思ってください.

  num = 3
  val = 5

は, 変数 num と val にそれぞれ 3 と 5 の数値を代入しています.
この後では, num を 3 の代わりに, val を 5 の代わりに使うことができます.

print 文は, num と val と num × val の値を画面に出力しています.

つまり, これは, 変数を使って 3 × 5 を計算するプログラムです.

では, コンパイルしてみましょう.

  $ gfortran -o variable variable.f90

しかし, このコンパイルは失敗します.
失敗する理由は, 使っている変数を宣言していないためです.
正しいプログラムは, 下のようになります. variable.f90 を変更してみましょう.

  program variable

    implicit none

    integer :: num      ! 追加した num の宣言文
    real    :: val      ! 追加した val の宣言文

    num = 3
    val = 5

    print *, num, val
    print *, "num * val = ", num * val

  end program variable

コンパイルして実行してみましょう.

  $ gfortran -o variable variable.f90     <- コンパイル
  $ ./variable                            <- 実行
           3   5.00000000
  num * val =    15.0000000

今回は無事にコンパイルが成功し, 実行することもできました.
このように, 変数は宣言した上で使います.

ただし, 変数を宣言するときには, 変数宣言の位置も重要です.
変数宣言文を下のように移動してみましょう.

  program variable

    implicit none

    num = 3
    val = 5

    integer :: num     ! 宣言文を移動
    real    :: val      ! 宣言文を移動

    print *, num, val
    print *, "num * val = ", num * val

  end program variable

このプログラムをコンパイルしてみると, エラーが出ます.

  $ gfortran -o variable variable.f90
  gfortran variable.f90
  variables.f90:8.56:

    integer :: num
    1
  Error: Unexpected data declaration statement at (1)
  ...

このエラーメッセージは, データの宣言文 (data declaration statement) が
予期しないところにあったという意味です.
データの宣言文はその他の実行文 (上の例では代入文 (num = 3)) よりも
前に書かなければいけません.

プログラムはエラーが出ないように, 宣言文の位置を元に戻しておきましょう.


== 変数の型

上のプログラムの例では, 変数 num と val の値, そして num と val の積が
表示されました.
しかし, num の値は 3 と整数として表示されるのに,
val の値は, 5.00000000 と実数として表示されていて,
それらの積も実数になっていることがわかります.
これは, num と val の宣言文を上のようにそれぞれ integer と real と
書いたためです.

上のプログラムの例では, num は

    integer :: num

と宣言し, val は

    real    :: val

と宣言しました.
これらの文はそれぞれ, 「num という変数を整数として使う」「val という変数を実数として使う」との宣言です.

一般に Fortran では, 下のような形式で変数を宣言して使います.

  <変数の型> :: <変数名>

そして, Fortran で予め用意されている変数の型には下の種類があります.

# RT
  delimiter = %

種類% データ型% 値の例
基本整数型% integer% 1, 2, 3, ...
8 バイト整数型% integer(8)% 1, 2, 3, ...
単精度実数型% real% 1.3582938e5 ("e5" は 10 の 5 乗を表す)
倍精度実数型% real(8) または double precision% 1.358293828395817d5 ("d5" は倍精度数値であり, 10 の 5 乗を表す)
複素数型% complex% 1.3582938e5 + 0.9283850e1 i (i は虚数単位を表す)
倍精度複素数型% complex(8) または double complex% 1.358293828395817d5 + 0.928385019381059d1 i
論理型% logical% .true. / .false.
文字型% character% "Hello world!"


上のプログラムの例では, num は小数点以下の桁を表すことのできない
整数型の変数であるため, 表示は 3 となっていました.
一方, val は実数型の変数であるため, 代入した値が整数の 5 であったとしても,
小数点以下の桁の値 (ゼロ) を表示したのです.

また, 変数に型があるように, Fortran プログラムの中では, 変数でない
数値 (上の例のプログラムでの 3 や 5) も, 何らかの型で表現されます.
(計算機内の表現の方法については, 講義で説明した通りです.)
例えば, 5 は整数として扱われ, 5.0 は実数として扱われます.
では, 倍精度実数として扱われる数値は何かというと, 5.0d0 と表現されます.
(その観点では, 実数として表される数値は, 正確には 5.0 ではなく 5.0e0 です.)
したがって, 正しく倍精度の数値を扱う際には, d0, あるいは 10 の 3 乗ならば d3 と表記すると良いでしょう.


では, 上に上げられているたくさんの型の変数を使ってみましょう.
下のようなプログラムを varmany.f90 のファイル名で作ってみてください.

プログラムを作るには,

  $ emacs varmany.f90

のように emacs でファイルを作ります.

  program varmany

    implicit none

    integer       :: numnum          ! 整数型変数の宣言
    real          :: val4val4         ! 実数型変数の宣言
    real(8)       :: val8val8         ! 倍精度実数型変数の宣言
    complex       :: compval4compval4     ! 複素数型変数の宣言
    complex(8)    :: compval8compval8     ! 倍精度複素数型変数の宣言
    logical       :: flagflag         ! 論理型変数の宣言
    character(20) :: line         ! (20) は最大 20 文字であることを表す文字型変数の宣言

    num      = 3
    val4     = 1.2
    val8     = 1.2d0
    compval4 = ( 1.2, 0.9 )       ! (実数部, 虚数部) として値を代入
    compval8 = ( 1.2d0, 0.9d0 )
    flag     = .true.
    line     = "test program"

    print *, "integer  : ", num
    print *, "real     : ", val4, ",", val8
    print *, "complex  : ", compval4, ",", compval8
    print *, "logical  : ", flag
    print *, "character: ", line

  end program varmany

注意:
* 上のプログラムをコピーアンドペーストすると, ダブルクォーテーション (") が
  全角文字としてペーストされることがあります.
  Fortran プログラムの命令文には, 全角文字は使えませんのでエラーになります.

コンパイルして実行すると下のように表示されるでしょう.

  $ gfortran -o varmany varmany.f90
  $ ./varmany
  integer  :            3
  real     :    1.20000005     ,   1.2000000000000000
  complex  :  (  1.20000005    , 0.899999976    ) , (  1.2000000000000000     , 0.90000000000000002     )
  logical  :  T
  character: test program


整数型, 単精度実数型, 倍精度実数型, 複素数型, 8 バイト複素数型倍精度複素数型, 論理型, 文字型の変数に値を代入した時, それぞれどのような値が保持されているかを
確認してみてください.

複素数型, 8 バイト複素数型の変数の出力は, === (倍精度)複素数型変数

複素数型, 倍精度複素数型の変数の出力は,

  ( 実数部, 虚数部 )

という表し方になっています.
プログラムでは, この書き方で複素数型変数に値を代入していて, print 文による
出力もこの形式になっています.

=== 文字型変数

上のプログラムでは, 文字型変数は

    character(20) :: line         ! 文字型変数の宣言

のように宣言しています. ここで (20) は最大 20 文字であることを表します.
(
なお, これは 20 個の文字型変数を保持する変数と考えて,
後で説明する「配列」とみなしても差し支えありません.)

文字型配列への代入は

    line     = "test program"

のように行っています. ここでは
, 文字列を表すために
ダブルクォーテーション (") を使って括っています.
ダブルクォーテーションの代わりにシングルクォーテーション (') を
使うこともできます.

=== 計算機での実数の表現の限界

単精度実数型の変数 val4 と倍精度実数型の変数 val8 の出力を
見てもわかる通り, 1.2 という数値が, 実数型の変数で正確に表現
することができていないことがわかります.
また, 複素数型の変数 compval4 および 8 バイト複素数型の倍精度複素数型の変数 compval8 の
出力からは, 0.9 という数値が正確に表現できていないこともわかります.
これらは, コンピュータでの実数の表現の誤差の結果です.

精密な計算を行うときには, このような誤差が計算結果に影響を及ぼさないように
気を付ける必要があるでしょう.


=== 整数型変数を用いた計算での注意事項

では, 変数の扱いについてもう一つ大切な注意点を説明しておきます.

下のプログラムを vardivide.f90 という名前で作成しましょう.

プログラムを作るには,

  $ emacs vardivide.f90 &

のように emacs でファイルを作ります.

  program vardivide

    implicit none

    integer :: num1, num2
    real    :: val41, val42
    real(8) :: val81, val82

    num1  = 1
    num2  = 3
    val41 = 1.0
    val42 = 3.0
    val81 = 1.0d0
    val82 = 3.0d0

    print *, "integer : ", num1/num2
    print *, "real    : ", val41/val42
    print *, "real(8) : ", val81/val82

  end program vardivide

補足:
* 上のプログラムの
    integer :: num1, num2
  の行からもわかる通り, 1 行に複数の変数を宣言することもできます.


上のプログラムは, 整数型変数, 実数型変数, 倍精度実数型変数を使って,
1 ÷ 2 を計算します.


コンパイルして実行すると下のように表示されるでしょう.

  $ gfortran -o vardivide vardivide.f90
  $ ./vardivide
  integer :            0
  real    :   0.333333343
  real(8) :   0.33333333333333331

結果を見ると, 実数型変数を使って計算した場合と, 倍精度実数型変数を
使って計算した場合には, ほぼ正確な計算結果 (0.3333...) が得られています.
(しかしながら, 無限に続く 3 を表現することはできませんので,
最後の方の桁では値がずれています.)

しかし, 整数型変数を使って計算した結果は 0 になっています.
これは, 整数型変数同士の演算の結果が整数型になってしまうことが
原因です.
したがって, 整数型変数を使って演算を行うときには, 結果が整数なのか
実数なのかに注意を払う必要があります.


== 定数

プログラムの中では, 二度と変化させることのない変数を使うことがよくあります.
例えば, 円周率などの数学定数や, 重力定数などの物理定数等がそれにあたるでしょう.

そういった変数の値は, プログラム中で間違って変更してしまわないように,
変数に「定数」としての属性を付けることができます.

実際に, 下のプログラムを varconst.f90 という名前で作成して試してみましょう.

プログラムを作るには,

  $ emacs varconst.f90 &

のように emacs でファイルを作ります.

  program varconst

    implicit none

    real, parameter :: pi = 3.141592   ! 円周率

    print *, pi

  end program varconst

このプログラムでは, 実数型変数の pi に "parameter" という属性を
付けています. このように属性を付けることで, この変数の値は
プログラム中で変更することができません.

コンパイルして実行すると下のように表示されるでしょう.

  $ gfortran -o varconst varconst.f90
  $ ./varconst
     3.14159203                  <- pi の値

では, pi の値を変更できないことを確認してみましょう.
上のプログラムを下のように変更してみましょう.

  program varconst

    implicit none

    real, parameter :: pi = 3.141592   ! 円周率

    print *, pi

    pi = 5.0               ! 追加した文
    print *, pi            ! 追加した文

  end program varconst

このプログラムをコンパイルしてみましょう.

  $ gfortran -o varconst varconst.f90

このプログラムはコンパイルできません.
pi が定数なので変更できない旨のエラーメッセージを確認できましたか?

このように, 変数に属性を付けることで, 様々な間違いに気づくことができます.
プログラムを作るときにはどうしても間違いを犯してしまうものです.
複雑なプログラムを作るときには, なおさらでしょう.
こういった機能を活用することで正しいプログラムを作りやすくなります.


== implicit none についての補足

実は Fortran の文法の規則では, 変数の宣言は必須ではありません (変数を
宣言せずに使う方法があります).
これまでに示してきた例のプログラムで, 宣言しないと変数を使えないのは,

  implicit none

の行があるからです.
上ではこの行は「おまじない」と説明しましたが, 実際には,
変数を宣言しないと使えないようにする命令です.
逆に言えば, implicit none を書かないことで, 宣言なしで変数を
使うことができます.
ここでは, そのような場合に, 変数が何型になるのかを説明しておきます.

implicit none を書かないプログラムでは, 変数は
下のような型を持ちます.


# RT
  delimiter = %

変数名% データ型
変数名の頭文字が a, b, ..., g, h, o, p, ..., y, z の場合 (例えば val)% real
変数名の頭文字が i, j, k, l, m, n の場合 (例えば num)% integer

実際に, 下のプログラムを varimplicit.f90 という名前で作成して試してみましょう.

プログラムを作るには,

  $ emacs varimplicit.f90 &

のように emacs でファイルを作ります.


  program varimplicit

    num      = 3
    val4     = 1.2
    val8     = 1.2d0

    print *, num
    print *, val4
    print *, val8

  end program varimplicit

このプログラムには implicit none の宣言がなく, また,
変数 num, val4, val8 の宣言文がないことに注意してください.

コンパイルして実行すると下のように表示されるでしょう.

  $ gfortran -o varimplicit varimplicit.f90
  $ ./varimplicit
            3              <- num の出力
     1.20000005            <- val4 の出力
     1.20000005            <- val8 の出力

このプログラムは, 変数 num, val4, val8 の宣言文がないにもかかわらず,
コンパイルに成功し, 実行することもできます.
この時, num の値は整数型 (3) であり, val4, val8 の値は,
両方ともに単精度実数型 (1.20000005) であることがわかります.

このように, Fortran の規則としては, 変数の宣言をしなくても,
変数を使うことができます.
しかし, その変数の型は, 自動的に決まってしまいます.
(これを「暗黙の型宣言」と呼びます.)

このように, 変数を宣言しなくても変数が使えることを, 便利と考える
こともできますが, 今の情報科学の考え方はそうではありません.
なぜならば, 例えば, 「暗黙の型宣言」によって, 打ち間違いによって
できた変数があってもエラーが出ないからです.
例えば, "val0" (「ブイ」「エー」「エル」「ゼロ」) と書くつもり
が "valO" (「ブイ」「エー」「エル」「(大文字)オー」) と打ち間違っ
たとします.
このとき, implicit none を書いていないプログラムでは, 二つの変数,
val0 と valO が使われていると解釈され, コンパイルに成功してしまいます.
しかし, プログラムに implicit none と書いておくと, 宣言しない
変数はエラーが出ますので,
"val0" と "valO" の打ち間違いに気づくことができます.

このような理由によって, 現在では, プログラムに implicit none を書いておく
ことが推奨されています.


== 変数の型についての補足

上では, Fortran で用意されている変数の型について説明しました.
Fortran 90 (以降) では, この他に, ユーザが定義する変数の型が存在します.
これは, C 言語での構造体によく似た型です.
惑星学実験実習の基礎IIでは, ユーザ定義型については解説しませんが,
興味があれば調べてみると良いでしょう.