この文書の URL は http://www.cc.kyoto-su.ac.jp/~mtkg/lecture/comp_B/2012/02.html です。
四則演算
次のプログラムを作成し加減乗除を試してみましょう。
割り算(商を求める演算子)は /
です。
! ! 加減乗除 ! program work0201 implicit none integer :: nx, ny write(*,*) 'Inputs two integers:' read(*,*) nx, ny write(*,*) 'nx + ny = ', nx + ny write(*,*) 'nx - ny = ', nx - ny write(*,*) 'nx * ny = ', nx * ny write(*,*) 'nx / ny = ', nx / ny stop end program work0201
プログラムを実行すると入力待ちの状態になります。
24 と 5 を空白で区切って入力しリターンキーを押すと、read 文の入力並びに書いた順番にしたがって
nx
に 24, ny
に 5 がセットされます。
% ./a.out Inputs two integers: 24 5 nx + ny = 29 nx - ny = 19 nx * ny = 120 nx / ny = 4
整数の割り算
割り算の結果に注意してください。
整数 / 整数
という計算では「商の整数部」(小数点以下を切り捨てた値)が得られます。
このため 24 / 5
は 4.8 にならず 4 になります。
平均値の計算
2つの整数値を読み込んで平均値を表示するプログラムを作成してみましょう。
ファイル名は work0202.f90
とします。
program work0202 implicit none integer :: nx, ny write(*,*) 'Inputs two integers:' read(*,*) nx, ny write(*,*) 'mean = ', (nx + ny) / 2 stop end program work0202
計算の優先順序
nx + ny
を ( )
で囲んで正しい順序で計算されるようにします。
Fortran では通常の演算規則と同じように演算の優先順序が決められています。
結果の型
いくつか試してみましょう。
% ./a.out Inputs two integers: 10 12 mean = 11 % ./a.out Inputs two integers: 10 13 mean = 11
10 と 12 の平均は正しく計算できていますが、10 と 13 の結果は変ですね。 Fortran では「整数 / 整数」の結果が整数になり、結果の小数部分が切り捨てられるので、このような結果になります。 平均を正しく計算するには次の「実数型」を使います。
実数型
Fortran では実数を浮動小数点数 (floating point number) という形式で表します。 実数型にはいくつかの種類がありますが、一般的には real(8) 型が使われます。
real(8) 型は次の範囲の実数を「近似的に」表すことができます。
- 最小値:
±2.225073858507201×10^(-308)
- 最大値:
±1.797693134862316×10^(+308)
- 精度: 10進数で約14桁 (2進数で53桁)
ここで 10^n
は 10 の n 乗を表すものとします。
整数型と実数型の性質の違いをみるために、次のようなプログラムを作成してみましょう。
program work0203 implicit none integer :: nx ! 整数型 real(8) :: dx ! 実数型 nx = 9.99 ! 整数型に実数を代入 dx = 9.99 ! 実数型に実数を代入 write(*,*) 'nx = ', nx write(*,*) 'dx = ', dx write(*,*) 'nx / 2 = ', nx / 2 write(*,*) 'dx / 2 = ', dx / 2 stop end program work0203
これを実行すると次のようになります。
% ./a.out nx = 9 dx = 9.9899997711181641 nx / 2 = 4 dx / 2 = 4.9949998855590820
この結果から次のことがわかります。
- 整数型の変数
nx
に実数値 9.99 を代入すると、小数部分が切り捨てられnx
には 9 が格納される。 - 実数型の変数
dx
に実数値 9.99 を代入しても正確に 9.99 が格納されるわけではない。 これは 9.99 が2進数では循環小数になるためである。 nx / 2
の計算では結果が整数型になり、小数部分が切り捨てられる。dx / 2
の計算では結果が実数型になり、小数部分の切り捨ては行われない。
型と演算
Fortran では、演算を構成している定数や変数の型がすべて同じ場合は、結果も同じ型になります。 例えば、「整数 / 整数」の結果は整数型、「実数 / 実数」の結果は実数型になります。
一方、「実数 / 整数」や「整数 / 実数」のように演算の対象が異なる型の場合は、整数型が実数型に変換されてから演算が行われます。 例えば、「5.0 / 2」という演算では 2 が 2.0 という実数型の数値に変換されてから計算されます。
こうした規則は割り算 /
だけでなく +
や -
, *
にも同様に適用されます。
定数の型
real(8) 型の定数は「10 を基数とする指数表現」を使って次のように表すことができます。
実数定数 意味 ----------------------------------------------------------------- 3.14d+0 3.14 x 10^0 --> 3.14 1.25d+3 1.25 x 10^3 --> 1250.0 0.8d-3 0.8 x 10^(-3) --> 0.0008
指数表現を使わずに「型パラメータ」を指定して表すこともできます。
12.0_8 12.0d+0 と同じ -0.2_8 -0.2d+0 と同じ
数字_8
の 8 は real(8) の 8 に対応しています。
この数字のことを型パラメータといいます。
注意
単に 3.14
などと書くと real(4) 型という精度の低い別の実数型になってしまうので注意しましょう。
real(4) 型は精度が10進数で約6桁(2進数で24桁)しかありません。
平均値の計算 (2)
2つの整数値を読み込んで平均値を「正しく」計算するプログラムを作成してみましょう。
ファイル名は work0204.f90
とします。
program work0204 implicit none integer :: nx, ny write(*,*) 'Inputs two integers:' read(*,*) nx, ny write(*,*) 'mean = ', (nx + ny) / 2.0d+0 stop end program work0204
実際に行われる計算
平均を求める式 (nx + ny) / 2.0d+0
に注目してみましょう。
work0202.f90
との違いは 2
が 2.0d+0
になっただけです。
計算機の中で行われる計算は次のようになります。
nx + ny
は整数型同士の演算です。したがって、この加算の結果は整数型になります。(nx + ny) / 2.0d+0
は「整数型 / 実数型」という演算になります。 整数型が実数型に変換されてから割り算が実行され、最終的な結果は実数型になります。
Fortran プログラミングでは常に「型」を意識することが大切です。
型変換の組込み関数
組込み関数 dble(整数型)
や real(整数型, kind=8)
を使うと、整数型の定数や変数を実数型
(real(8) 型)に変換することができます。
したがって、平均を求める式は次のように書くこともできます。
dble(nx + ny) / 2 real(nx + ny, kind=8) / 2
この場合は nx + ny
の結果(整数型)が実数型に変換され、「実数型 / 2」の計算が行われます。
整数型の定数 2 は自動的に実数型に変換され、演算の結果は実数型になります。
Fortran には実数型を整数型に変換する組込み関数も用意されています。
int(x) 小数部分を切り捨てて整数化する。 nint(x) 実数 x にもっとも近い整数を返す。
符号の反転
値の符号を反転させるには -
演算子を使います。
program work0205 implicit none integer :: nx write(*,*) 'Inputs an integer:' read(*,*) nx write(*,*) '-nx = ', -nx stop end program work0205
符号を変化させない +
演算子もありますが、ほとんど使われません。
剰余
2つの整数値を読み込んで、その商と剰余(割り算の余り)を表示してみましょう。 整数 a を整数 b で割った余りを計算するには、
a - (a を b で割った商の整数部分) * b
を計算すればよいですね。
a, b が整数型なので a / b
が「a を b で割った商の整数部分」になります。
program work0206 implicit none integer :: nx, ny write(*,*) 'Inputs two integers:' read(*,*) nx, ny write(*,*) 'div = ', nx / ny write(*,*) 'mod = ', nx - (nx / ny) * ny stop end program work0206
正しく計算できるか確かめてみましょう。
% ./a.out Inputs two integers: 27 6 div = 4 mod = 3
練習問題
剰余は mod
という組込み関数(あらかじめ用意されている関数のこと)を使って計算することもできます。
mod(a, b)
で整数 a を整数 b で割った余りが計算されます。
上の例に
write(*,*) 'mod = ', mod(nx, ny)
を加えて試してみましょう。
本日の課題
1. 組込み関数 int
組込み関数 int
を利用して、キーボードから読み込んだ実数の小数部分を求めるプログラムを作成せよ。
ある実数の小数部分を求めるには整数部分を引けばよい。
program work0207 implicit none real(8) :: dx write(*,*) 'Input a real:' read(*,*) dx write(*,*) dx - int(dx) stop end program work0207
2. 相加平均と相乗平均
2つの実数を読み込んで、相加平均と相乗平均を計算するプログラムを作成せよ。
相乗平均の計算には平方根を計算する sqrt(実数型)
という組込み関数を利用する。
program work0208 implicit none real(8) :: dx, dy write(*,*) 'Input two reals:' read(*,*) dx, dy write(*,*) 'souka = ', (dx + dy) / 2 write(*,*) 'soujo = ', sqrt(dx * dy) stop end program work0208
3. いろいろな平均
3つの実数を読み込んで算術平均、幾何平均、調和平均を計算するプログラムを作成せよ。 3つの数 X, Y, Z の算術平均 A, 幾何平均 G, 調和平均 H は次のように定義される。
A = (X + Y + Z) / 3 G = (X * Y * Z)**(1/3) 1/H = (1/X + 1/Y + 1/Z) / 3
立方根の計算にはべき乗の演算子 **
を利用する。
x**y
は x の y 乗を表す。
したがって、実数型の変数 dx, dy, dz の積の立方根 (1/3 乗) を計算するには
(dx * dy * dz)**(1.0d+0 / 3)
とすればよい。
(dx * dy * dz)**(1 / 3)
では (dx * dy * dz)**0
になってしまうので注意すること。
! ! いろいろな平均 ! program work0209 implicit none real(8) :: x, y, z real(8) :: a, g, h write(*,*) 'Input three potitive reals:' read(*,*) x, y, z a = (x + y + z) / 3 g = (x * y * z)**(1.0d+0 / 3) h = (1/x + 1/y + 1/z) / 3 ! h には 1/H が入る h = 1 / h ! 1/H => H write(*,*) a, g, h stop end program work0209