IT pass HikiWiki - [itbase2017]Fortran 実習 入出力 Diff
- Added parts are displayed like this.
- Deleted parts are displayed
like this.
{{toc}}
データ解析や数値計算には入力データが必要なことが多いでしょう.
また, 解析結果や計算結果は何かしらの形で出力しなければなりません.
ここでは, Fortran での入出力を簡単に体験してみましょう.
= 注意
* 前回説明したように, Fortran のプログラムの実行のためには, エディタでプログラムを書くだけでなく, 「コンパイル」する必要があります.
* 今回の資料では, プログラムのコンパイル方法の詳細は説明していません.
* 意味が解らなければ前回の資料を復習しましょう.
= 入出力文
== 入力文
Fortran では下に示す入力の命令が用意されています.
# RT
delimiter = %
命令% 入力元 % 使用例
read % キーボードとファイル % read( 5, * ) num
ここで read の引数の "5" と "*" はそれぞれ「装置番号」と「書式」を
表しています. これらについては後で説明します.
なお, read 文には, 装置番号と書式の他にも様々な指定が可能です.
興味があれば調べてみると良いでしょう.
== 出力文
Fortran では下に示す出力の命令が用意されています.
# RT
delimiter = %
命令% 出力先 % 使用例
print % 画面 % 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
write( 6, * ) "Input a number:" ! 入力を促す
read ( 5, * ) val ! キーボード (装置番号 5) から読み込み
write( 6, * ) "Inputted number:", val ! 読み込んだ値の表示
end program inputfromkb
この例では, 一つ目の write 文で数値の入力を促し,
read で値を読み込み,
二つ目の write 文で入力した数値を表示しています.
このプログラムをコンパイルして作った実行ファイル inputfromkb を
実行すると下のようになります.
(プログラムは "Input a number:" と表示して数値の入力を促しますので, キーボードから数値を入力する必要があります.)
$ ./inputfromkb
Input a number:
123.4567 <- キーボードから数値を入力する
Inputted number: 123.456703 <- プログラムが数値を出力
= 書式
上に書いた 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 に対する書式指定に対応します.
それぞれ下のような意味になります.
# RT
delimiter = %
書式指定 % 意味 % 備考
i5 % 整数全 5 桁 %
f5.2 % 実数全 5 桁, 小数点以下 2 桁 % 全 5 桁には小数点と空白を含む
e10.2 % 実数全 10 桁, 小数点以下 2 桁 (mmE+-nn の形式) % 全 10 桁には小数点と空白と指数の E, + も含む
a1 % 文字列 1 文字 %
x % 空白 1 文字 % 空白文字 " " を書いて a1 と書式指定しても同じ.
その他のものも含めると, 指定に使う文字 (変換記号) には下のような
ものがあります.
# RT
delimiter = %
書式指定 % 意味 % 使用例 % 123 を出力した時の結果
i % 整数型 % i5 % " 123"
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 文を指定するために使われているラベルです.
上の例では, 101 番の format 文は一つの write 文でしか使っていませんが,
複数の write 文で同じ format 文を使うこともできます.
このような書式指定をすることで, 出力の見た目を整え, 結果を
わかりやすく示すことができます.
== 練習問題
上に示したプログラム outputnum.f90 を変更して,
プログラムの実行結果の出力が下のように 1 行目と 2 行目が
揃うように書式指定と出力変数を工夫してみましょう.
(やり方は複数あり得ます. 思いついた方法で好きなようにやってみましょう.)
出力結果の例
$ ./outputnum
1 , 1.23456788 ,1.23456789012345671.23456788
1 , 1.23 , 0.12E+01
# 1 , 1.23456788 , 1.2345678901234567
# 1 , 1.23 , 0.12E+01
= ファイルからの入力/への出力
== ファイルを開く
Fortran でファイルを開くためには例えば下のような open 文を用います.
open( 11, file = "test.txt", status = "unknown" )
一般的には,
open( <装置番号>, file = <ファイル名>, status = <ステータス>, ... )
となります.
<装置番号> は, read 文や write 文で説明したものと同じものです.
つまり, open は, ファイル名と装置番号を関連付けており,
ファイルからの入力やファイルへの出力には, その入力元/出力先の
ファイルに対応した装置番号を指定します.
ステータスには下に示すような種類を指定することができます.
# RT
delimiter = %
ステータス % 意味
unknown % 「適当に」開く (読み込みでも書き込みでも)
old % 読み込み用に開く
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
10
15
また, 下のようなプログラムを inputfromfile.f90 というファイル名で
作成し, 実行しましょう.
program inputfromfile
implicit none
integer :: val
open( 11, file="input.txt", status="old" ) ! ファイルを開く
read ( 11, * ) val ! ファイルから数値を一つ入力
write( 6, * ) val ! 画面に数値を出力
read ( 11, * ) val
write( 6, * ) val
read ( 11, * ) val
write( 6, * ) val
close( 11 )
end program inputfromfile
このプログラムは, input.txt から数値を入力し, それを画面に出力しています.
read 文一つにつき, 一つの数値を読んでいることに注意しましょう.
read 文では基本的には 1 行ずつ読み込みます.
== 練習問題
上で使った inputfromfile.f90 を基にして, input.txt に保存されている
数字を読み込み, その和を求めて, その値をファイル output.txt に
出力するプログラムを作りなさい.
データ解析や数値計算には入力データが必要なことが多いでしょう.
また, 解析結果や計算結果は何かしらの形で出力しなければなりません.
ここでは, Fortran での入出力を簡単に体験してみましょう.
= 注意
* 前回説明したように, Fortran のプログラムの実行のためには, エディタでプログラムを書くだけでなく, 「コンパイル」する必要があります.
* 今回の資料では, プログラムのコンパイル方法の詳細は説明していません.
* 意味が解らなければ前回の資料を復習しましょう.
= 入出力文
== 入力文
Fortran では下に示す入力の命令が用意されています.
# RT
delimiter = %
命令% 入力元 % 使用例
read % キーボードとファイル % read( 5, * ) num
ここで read の引数の "5" と "*" はそれぞれ「装置番号」と「書式」を
表しています. これらについては後で説明します.
なお, read 文には, 装置番号と書式の他にも様々な指定が可能です.
興味があれば調べてみると良いでしょう.
== 出力文
Fortran では下に示す出力の命令が用意されています.
# RT
delimiter = %
命令% 出力先 % 使用例
print % 画面 % 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
write( 6, * ) "Input a number:" ! 入力を促す
read ( 5, * ) val ! キーボード (装置番号 5) から読み込み
write( 6, * ) "Inputted number:", val ! 読み込んだ値の表示
end program inputfromkb
この例では, 一つ目の write 文で数値の入力を促し,
read で値を読み込み,
二つ目の write 文で入力した数値を表示しています.
このプログラムをコンパイルして作った実行ファイル inputfromkb を
実行すると下のようになります.
(プログラムは "Input a number:" と表示して数値の入力を促しますので, キーボードから数値を入力する必要があります.)
$ ./inputfromkb
Input a number:
123.4567 <- キーボードから数値を入力する
Inputted number: 123.456703 <- プログラムが数値を出力
= 書式
上に書いた 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 に対する書式指定に対応します.
それぞれ下のような意味になります.
# RT
delimiter = %
書式指定 % 意味 % 備考
i5 % 整数全 5 桁 %
f5.2 % 実数全 5 桁, 小数点以下 2 桁 % 全 5 桁には小数点と空白を含む
e10.2 % 実数全 10 桁, 小数点以下 2 桁 (mmE+-nn の形式) % 全 10 桁には小数点と空白と指数の E, + も含む
a1 % 文字列 1 文字 %
x % 空白 1 文字 % 空白文字 " " を書いて a1 と書式指定しても同じ.
その他のものも含めると, 指定に使う文字 (変換記号) には下のような
ものがあります.
# RT
delimiter = %
書式指定 % 意味 % 使用例 % 123 を出力した時の結果
i % 整数型 % i5 % " 123"
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 文を指定するために使われているラベルです.
上の例では, 101 番の format 文は一つの write 文でしか使っていませんが,
複数の write 文で同じ format 文を使うこともできます.
このような書式指定をすることで, 出力の見た目を整え, 結果を
わかりやすく示すことができます.
== 練習問題
上に示したプログラム outputnum.f90 を変更して,
プログラムの実行結果の出力が下のように 1 行目と 2 行目が
揃うように書式指定と出力変数を工夫してみましょう.
(やり方は複数あり得ます. 思いついた方法で好きなようにやってみましょう.)
出力結果の例
$ ./outputnum
1 , 1.23456788 ,
1 , 1.23 , 0.12E+01
# 1 , 1.23456788 , 1.2345678901234567
# 1 , 1.23 , 0.12E+01
= ファイルからの入力/への出力
== ファイルを開く
Fortran でファイルを開くためには例えば下のような open 文を用います.
open( 11, file = "test.txt", status = "unknown" )
一般的には,
open( <装置番号>, file = <ファイル名>, status = <ステータス>, ... )
となります.
<装置番号> は, read 文や write 文で説明したものと同じものです.
つまり, open は, ファイル名と装置番号を関連付けており,
ファイルからの入力やファイルへの出力には, その入力元/出力先の
ファイルに対応した装置番号を指定します.
ステータスには下に示すような種類を指定することができます.
# RT
delimiter = %
ステータス % 意味
unknown % 「適当に」開く (読み込みでも書き込みでも)
old % 読み込み用に開く
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
10
15
また, 下のようなプログラムを inputfromfile.f90 というファイル名で
作成し, 実行しましょう.
program inputfromfile
implicit none
integer :: val
open( 11, file="input.txt", status="old" ) ! ファイルを開く
read ( 11, * ) val ! ファイルから数値を一つ入力
write( 6, * ) val ! 画面に数値を出力
read ( 11, * ) val
write( 6, * ) val
read ( 11, * ) val
write( 6, * ) val
close( 11 )
end program inputfromfile
このプログラムは, input.txt から数値を入力し, それを画面に出力しています.
read 文一つにつき, 一つの数値を読んでいることに注意しましょう.
read 文では基本的には 1 行ずつ読み込みます.
== 練習問題
上で使った inputfromfile.f90 を基にして, input.txt に保存されている
数字を読み込み, その和を求めて, その値をファイル output.txt に
出力するプログラムを作りなさい.