[itbase2021]Fortran 実習 入出力
データ解析や数値計算には入力データが必要なことが多いでしょう. また, 解析結果や計算結果は何かしらの形で出力しなければなりません. ここでは, Fortran での入出力を簡単に体験してみましょう.
注意
- 前回説明したように, Fortran のプログラムの実行のためには, エディタでプログラムを書くだけでなく, 「コンパイル」する必要があります.
- 今回の資料では, プログラムのコンパイル方法の詳細は説明していません.
- 意味が解らなければ前回の資料を復習しましょう.
入出力文
入力文
Fortran では下に示す入力の命令が用意されています.
命令 | 入力元 | 使用例 |
read | キーボードとファイル | read( 5, * ) num |
ここで read の引数の "5" と "*" はそれぞれ「装置番号」と「書式」を 表しています. これらについては後で説明します.
なお, read 文には, 装置番号と書式の他にも様々な指定が可能です. 興味があれば調べてみると良いでしょう.
出力文
Fortran では下に示す出力の命令が用意されています.
命令 | 出力先 | 使用例 |
画面 | print *, 5.0 | |
write | 画面とファイル | write( 6, * ) 5.0 |
print は画面にしか出力できませんが, write はそれに加えて ファイルに出力することもできますので, write の方が用途が 広いことになります.
ここで print および write の引数の "6" と "*" はそれぞれ 「装置番号」と「書式」を表しています. これらについては後で説明します.
装置番号
read と write で入出力する際に, 入力元や出力先を 指定するために使うのが装置番号です.
上の read/write の使用例では, 5 と 6 がそれらに対応します. 装置番号の 5 と 6 は特別な番号で, 5 はキーボード (「標準入力」とも呼びます) を表し, 6 は画面 (「標準出力」とも呼びます) を表します.
従って,
read( 5, * ) num
と
write( 6, * ) 5.0
はそれぞれ, キーボード (標準入力) からの読み込みと画面 (標準出力) への 出力を表しています.
5, 6 以外の数字は, ユーザが決めることができて, ファイルに割り当てて 入出力に使います.
キーボードから入力と画面への出力の例
下のようなプログラムを inputfromkb.f90 というファイル名で作成して 実行してみましょう.
program inputfromkb implicit none real :: val real :: val2 write( 6, * ) "Input a number:" ! 入力を促す read ( 5, * ) val ! キーボード (装置番号 5) から読み込み write( 6, * ) "Input number:", val ! 読み込んだ値の表示 write( 6, * ) "Input two numbers:" ! 入力を促す read ( 5, * ) val, val2 ! キーボード (装置番号 5) から読み込み write( 6, * ) "Input numbers:", val, val2 ! 読み込んだ値の表示 end program inputfromkb
この例では, 一つ目の write 文で数値の入力を促し, read で値を読み込み, 二つ目の write 文で入力した数値を表示しています.
このプログラムをコンパイルして作った実行ファイル inputfromkb を 実行すると下のようになります. (プログラムは "Input a number:" と表示して数値の入力を促しますので, キーボードから数値を入力する必要があります.)
$ ./inputfromkb Input a number: 123.4567 <- キーボードから数値を入力する Input number: 123.456703 <- プログラムが数値を出力 Input two numbers: 123.4567 890.123 <- キーボードから数値を入力する Input numbers: 123.456703 890.123 <- プログラムが数値を出力
書式
上に書いた read, print, write の使用例に現れる "*" は「書式」の指定 を表します. ここで言う書式とは, 例えば数値を出力する際に, 何桁で出力するのかを 意味します.
上の例で示している "*" の指定は最も簡単で, 「適当に」入出力する指定です.
例えば, 下のプログラムを outputnum.f90 というファイル名で作成し, コンパイルして実行してみましょう.
program outputnum implicit none integer :: num real :: val num = 1 val = 1.234567890 write( 6, * ) num, ",", val, ",", val write( 6, "(i5, x, a1, f5.2, x, a1, e10.2)" ) num, ",", val, ",", val end program outputnum
例えばこのプログラムをコンパイルして作った実行ファイル outputnum を 実行すると下のようになります.
$ ./outputnum 1 , 1.23456788 , 1.23456788 1 , 1.23 , 0.12E+01
書式に "*" を指定したことで, 1 行目は「適当に」出力されていますが, 2 行目は "(i5, x, a1, f5.2, x, a1, e10.2)" に従って出力になっています. この指定のそれぞれは下のような意味があります.
"(i5, a1, f5.2, a1, e10.2)" の指定は, i5 が num に対する書式指定, x が空白 1 文字を書く指定, a1 が一つ目の "," に対する書式指定, f5.2 が一つ目の val に対する書式指定, a1 が二つ目の "," に対する書式指定, x が空白 1 文字を書く指定, e10.2 が一つ目の val に対する書式指定に対応します. それぞれ下のような意味になります.
書式指定 | 意味 | 備考 |
i5 | 整数全 5 桁 | |
i5.5 | 整数全 5 桁 | 値が 5 桁に満たない場合は 5 桁になるようにゼロで埋められる |
f5.2 | 実数全 5 桁, 小数点以下 2 桁 | 全 5 桁には小数点と空白を含む |
e10.2 | 実数全 10 桁, 小数点以下 2 桁 (mmE+-nn の形式) | 全 10 桁には小数点と空白と指数の E, + も含む |
a1 | 文字列 1 文字 | |
x | 空白 1 文字 | 空白文字 " " を書いて a1 と書式指定しても同じ. |
その他のものも含めると, 指定に使う文字 (変換記号) には下のような ものがあります.
書式指定 | 意味 | 使用例 | 123 を出力した時の結果 |
i | 整数型 | i5 | " 123" |
i5.5 | "00123" | ||
f | 実数型 | f7.2 | " 123.00" |
e | 実数型, mmE+-nn の形式 | e9.2 | " 0.12E+03" |
d | 倍精度実数型, mmE+-nn の形式 | d9.2 | "0.12D+03" |
l | 論理型 | - | - |
a | 文字型 | - | - |
x | 空白 | - | - |
注意: 上の表における, 「123 を出力した時の結果」にある ダブルクォーテーションは出力されません. 数値の前に空白が入ることを 表すために書いています.
また, 同じ指定を繰り返す時には, まとめて指定することもできます. 例えば, 下のような出力,
write( 6, "(i5, x, a1, i5, x, a1, e10.2)" ) num, ",", num, "," val
では, i5, x, a1 が 2 回繰り返されています. これらはまとめて,
write( 6, "(2(i5, x, a1), e10.2)" ) num, ",", num, ",", val
とすることもできます.
format 文
書式指定が長くなる場合, あるいは, 同じ書式を何度も使う場合には, 下のように書式を別の行に書くこともできます.
program outputnumformat implicit none integer :: num real :: val real :: val2 num = 1 val = 1.234567890 val2 = 0.987654321 write( 6, * ) num, ",", val, ",", val write( 6, 101 ) num, ",", val, ",", val write( 6, 101 ) num, ",", val2, ",", val2 101 format( i5, a1, f5.2, a1, e10.2 ) end program outputnumformat
ここで使われているのは format 文で, 書式指定のための命令文です. そして, 101 は, その format 文を指定するために使われているラベルです. 複数の write 文で同じ format 文を使うこともできます.
このような書式指定をすることで, 出力の見た目を整え, 結果を わかりやすく示すことができます.
ファイルからの入力/への出力
ファイルを開く
Fortran でファイルを開くためには例えば下のような open 文を用います.
open( 11, file = "test.txt", status = "unknown" )
一般的には,
open( <装置番号>, file = <ファイル名>, status = <ステータス>, ... )
となります.
<装置番号> は, read 文や write 文で説明したものと同じものです. つまり, open は, ファイル名と装置番号を関連付けており, ファイルからの入力やファイルへの出力には, その入力元/出力先の ファイルに対応した装置番号を指定します.
ステータスには下に示すような種類を指定することができます.
ステータス | 意味 |
unknown | 「適当に」開く (読み込みでも書き込みでも) |
old | 既に存在するファイルを開く (ファイルが存在しないとエラーになる) |
new | 新規作成用に開く (既にファイルが存在するとエラーになる) |
replace | 新規作成用に開く (既にファイルが存在すると内容は上書きされる) |
open 文には, 装置番号, ファイル名, ステータス以外にも, 様々な 指定が可能です. それらを使うことでかなり柔軟な処理が可能になります. ここでは詳細を説明しませんが, 興味があれば調べてみると良いでしょう.
ファイルを閉じる
Fortran でファイルを閉じるためには下のような close 文を用います.
close( 11 )
一般的には,
close( <装置番号> )
となります.
<装置番号> は, read/write/open 文で説明したものと同じものです. open 文で開いたファイルを閉じるときに, 対応する装置番号を指定します.
ファイルへの出力の例
下のようなプログラムを outputtofile.f90 というファイル名で作成して 実行してみましょう.
program outputtofile implicit none real :: val write( 6, * ) "Input a number:" ! 入力を促す read ( 5, * ) val ! キーボードから入力 open( 11, file="output.txt", status="replace" ) ! ファイルを開く write( 11, * ) val ! ファイルへの出力 close( 11 ) ! ファイルを閉じる end program outputtofile
このプログラムでは, キーボードから入力した数値をファイル, output.txt, に 出力しています. 実行した後で, ファイルができているかどうか, また, ファイルの中に 数値が保存されているかどうかを確認しましょう.
ファイルからの入力の例
ファイルからの入力を試すために, 入力データを用意しましょう.
emacs を使って, input.txt という名前のファイルに下の内容を書き込みましょう.
5 105 10 110 15 115
また, 下のようなプログラムを inputfromfile.f90 というファイル名で 作成し, 実行しましょう.
program inputfromfile implicit none integer :: val, val2 open( 11, file="input.txt", status="old" ) ! ファイルを開く read ( 11, * ) val ! ファイルから数値を一つ入力 write( 6, * ) val ! 画面に数値を出力 read ( 11, * ) val write( 6, * ) val read ( 11, * ) val, val2 write( 6, * ) val, val2 close( 11 ) end program inputfromfile
実行すると下のようになるでしょう.
$ ./inputfromfile 5 10 15 115
このプログラムは, input.txt から数値を入力し, それを画面に出力しています. read 文一つにつき, 一つの数値を読んでいることに注意しましょう. read 文では基本的には 1 行ずつ読み込みます.
練習問題
上で使った inputfromfile.f90 を基にして, input.txt に保存されている 数字を読み込み, その和を求めて, その値をファイル output.txt に 出力するプログラムを作りなさい.
Keyword(s):
References:[[itbase2021]惑星学実験実習の基礎II]