5.2. 四則演算 37
10 product = a*b;
11 quotient = a/b;
12 remainder= a%b;
13 printf("\nInput data: %d, %d\n\n"
14 "Sum: %d\n"
15 "Difference: %d\n"
16 "Product: %d\n"
17 "Quotient: %d\n"
18 "Remainder: %d\n",
19 a, b, sum, diff, product, quotient, remainder);
20 return 0;
21 }
[motoki@x205a]$ gcc -o arith-op arithmetic-operations-over-int.c Enter ... (実行ファイルの名前を指定してコンパイル) [motoki@x205a]$ ./arith-op Enter... (実行) 11 3 Enter... (データの入力) Input data: 11, 3
Sum: 14
Difference: 8 Product: 33 Quotient: 3 Remainder: 2 [motoki@x205a]$
ここで、
• プログラムの1〜2行目 は注釈。
• プログラムの3行目 は、/usr/include/stdio.h というファイルの中身をこの場所に 挿入してコンパイル作業を行うことを指示する。
• プログラムの4〜21行目 はmain関数の定義。
• プログラムの6行目 は、整数データを格納するための領域を7つ確保し、それぞれa, b, sum, diff, product, quotient, remainderと名付けることをコンパイラに知らせ る宣言文である。「int」と指定することにより、確保した領域が 整数データの内部 表現形式(3.4節) に従ってデータを保持する様になる。
'
&
$
% 補足:
intの様に、内部表現形式に起因するデータの種類を一般にデータ型(data type) と呼ぶ。C言語においては、intは整数を表すための最も標準的な内部表現形式 に対応したデータ型である。intの他には実数データを保持するためのfloat や
doubleといった(基本)データ型も用意され、また、(基本)データ型を複数組み
合わせて新しいデータ型を定義することもできる。=⇒第11節を参照。
• プログラミング(programming;i.e.プログラム作成の作業)の際には、a,b, sum, ... の 様に、プログラムの中でデータを記憶するために確保され使われる記憶領域のことを
一般に変数(variable)と呼ぶ。
'
&
$
% 変数の名前の付け方:
C言語では、変数に付ける名前として、
英字(または下線)で始まり、それに英数字や下線が続く文字の並び
を使うことが出来る。(大文字と小文字は区別する。)こういった制約の下で、使 い方/役割に応じた適切な名前を付けることが大切である。=⇒p.44を参照。
補足:
「変数」という用語は数学にも出て来る。プログラミングの場合も数学の場合も 元々の英語の用語は“variable”で、ともに
使う時点によって 表す対象/内容が変わり得るもの という意味である。
確かに、数学で 「関数f(x) =x2+ 1」 と言った場合の変数xは実数上で色々 と変わる値を表すものだし、プログラムにおける変数 aはプログラムの実行状 況に応じて色々な値を保持するもの(記憶領域)になっている。
• プログラムの7行目 は標準ライブラリの中に用意されている書式付き入力の関数scanf を呼び出している。 この呼出しの際にscanf関数に引き渡されるデータ(引数,ひきす
う, またはパラメータと言う) を指定しているのが、“scanf” に続く丸括弧 ( ) で囲 まれた部分である。各々の引数はコンマで区切られているので、7行目には全部で3 つの引数が指定されていることになる。このうち、第1引数は入力の書式を表す文字 列、2番目以降の引数は入力データを格納する領域の番地(address)を表している。こ こで指定された入力書式の中の%d は、読み込んだデータ(数字の列)を 整数 の内部 表現形式に変換して、然るべき記憶領域に格納することを指示している。 また、例 えば第2引数の &a は変数a (が置かれる主記憶上)の番地を表す。
'
&
$
% 補足:
単にaと書いたのでは変数aの保持する値がscanf関数に送られてしまい、
scanf側では読み込んだデータの格納場所が分からない。
• プログラムの8行目 は sum←− a + b すなわち
(変数a に保持されている値) + (変数 b に保持されている値) を計算して、その結果を変数 sumに格納する
という動作を表しています。 同様に、プログラムの9〜12行目 は各々 diff←− a −b,
product←− a × b,
quotient←− a ÷ b, . . . ( 小数部は捨てられ、結果は整数になる ) remainder←− (aの値)を(bの値)で割った時の余り,
という動作を表しています。
• プログラムの13〜19行目 は、標準ライブラリの中に用意されている書式付き出力の
関数 printf を呼び出している。13〜18行目の、2重引用符で囲まれた部分が出力書
式になっていて、この指示に従った様式で関数printfの第2引数以下(19行目)の部分 で指定された式の値が順に出力される。 [13〜18行目は途中にコンマが無いので、
1つの引数として扱われる。2重引用符で囲まれた文字列が6つ並んでいるが、この 部分はこれらの文字列を並べた1つの文字列と同等である。] これにより、結局次 のような出力がなされる。但し、ここでは空白は と明示している。
5.2. 四則演算 39
空行
Input data: 第2引数で指定された式aの値, 第3引数で指定された式bの値 空行
Sum: 第4引数で指定された式sumの値
Difference: 第5引数で指定された式diffの値
Product: 第6引数で指定された式productの値
Quotient: 第7引数で指定された式quotientの値
Remainder: 第8引数で指定された式remainderの値
ここで注目すべき点は次の通りである。
3 出力書式中に現れる %d という部分が第2引数以降の式と順にペアにされ、式の
値(を我々が見える文字列で表したもの)に置き換えられる。
3 出力書式中の \n は改行を指示する。
3 出力書式中の%d は別途指定された式の値が固定小数点数型(整数型)の内部表現 形式に従っていると仮定して、これを10進の文字列に変換して、この%dの場所 に出力することを指示する。
3 出力書式中の \n, %d 以外の文字列はそのまま出力される。
• gccコマンドの次に -o ファイル名 という形のオプションを入れると実行ファイル の名前を指定することができる。 上のコンパイル例の場合は、これによってarith-op という名前の実行ファイルが作られている。
代入文: “sum=a+b;”の様に、プログラムの中で
式の計算をして その結果を指定された変数に格納する動作を表す部分
を一般に代入文(assignment statement) と呼ぶ。特にC言語においては、変数名や 123 といった数を表す文字列に 8〜12行目の演算子や丸括弧を組み合わせて色々な 式を構成 し、
変数名 = 式 ;
変数名 += 式 ; . . . .( 変数名 = 変数名 + 式 ; と同等 ) 変数名 -= 式 ; . . . .( 変数名 = 変数名 - 式 ; と同等 ) 変数名 *= 式 ; . . . .( 変数名 = 変数名 * 式 ; と同等 ) 変数名 /= 式 ; . . . .( 変数名 = 変数名 / 式 ; と同等 ) 変数名 %= 式 ; . . . .( 変数名 = 変数名 % 式 ; と同等 )
...
という形の代入文を書くことができる。
例 5.4 (代入文) int型変数sum, x に関して、次の2つの代入文は同じ計算を行う。
sum = sum + x;
sum += x;
算術式の計算: (コンピュータによる)代入文の実行においては、等号の右側の算術式の 計算は通常の数学と同じ順序で1つずつ行われる。 すなわち、丸括弧によって計算の順 序が指定されていない場合、
• 乗除算, 剰余演算(*, /, %)を加減算(+, -)より先に行う。
• 乗除算, 剰余演算(*, /, %)の間では、左にあるものを優先する。
• 加減算(+, -)の間では、左にあるものを優先する。
当然、途中で行われる各々の演算の結果はコンピュータの中に(一時的に)保持されなけ ればならず、演算結果を保持する内部表現形式も決まっているはずである。 そのために、
算術式を構成する各々の(部分)算術式に対して、そのデータ型が定められている。 特に int型データ同士の演算の場合は、演算結果はint型と定められている。
例 5.5 (算術式における演算順序の指定) int型変数 h, m, s, timeに関して、次の4つ の代入文は同等の計算結果をもたらす。
time = h*60*60 + m*60 + s;
time = (((h*60)*60) + (m*60)) + s;
time = (h*60 + m)*60 + s;
time = h*3600 + m*60 + s;
例 5.6 (式の計算に関する注意) int型同士の除算においては商の小数部は捨てられる。そ
のため、数学的に等しい式であっても、C言語の算術式としては異なる値を持つことがあ る。例えば、数学的には 1/2∗a=a∗1/2 であるが、大抵の場合2つの代入文 x=1/2*a;
と x=a*1/2; は異なる実行結果をもたらす。 実際、x=1/2*888; を実行すると変数 x に は値 0が格納され、x=888*1/2; を実行すると変数 x には444 という値が格納される。
例題 5.7 (直方体の体積) 3つの整数データ x, y, a を読み込み、それらを使って 縦,横が各々 xcm, ycm の厚紙の四隅をacm 四方だけ切り取ってできる直方体 の体積を計算して出力するCプログラムを作成せよ。
a
x
y
この処理のために、 厚紙の縦,横,切り取る正方形 の一辺の長さを記憶する領域を用意し各々 x, y, a という名前を付けることにする。すると、縦がx-2*a cm, 横が y-2*a cm, 高さが a cm の直方体が出来る から、求める体積は(x-2*a)*(y-2*a)*a と計算でき る。そこで、データ入力を促す文字列も出すことに
し、またprintf 関数を使って算術式の計算結果を変
数に格納せずにそのまま出力することにすれば、コン ピュータが行うべき処理は右図の様に書き表すことが できる。
開始
入力 (プロンプト付き) x, y, a
x, y, a は正整数で a<x, a<y と仮定
終了
出力 "==> 直方体の体積 = ", (x-2*a)*(y-2*a)*a
5.2. 四則演算 41
この処理を行うCプログラムと、これをコンパイル/実行している様子は次に示す通りで
ある。 (下線部はキーボードからの入力を表す。)
[motoki@x205a]$ nl rectangular-parallelepiped.c
1 /* 3つの整数データ x, y, a を読み込み、それらを使って */
2 /* 縦,横が各々 x,y の厚紙の四隅を a 四方だけ */
3 /* 切り取ってできる直方体 */
4 /* の体積を計算して出力するCプログラム */
5 #include <stdio.h>
6 int main(void) 7 {
8 int x, y, a;
9 printf("厚紙の縦 = ? ");
10 scanf("%d", &x);
11 printf("厚紙の横 = ? ");
12 scanf("%d", &y);
13 printf("切り取る正方形の一辺 = ? ");
14 scanf("%d", &a);
15 printf("\n==> 直方体の体積 = %d 立方cm\n", 16 (x-2*a)*(y-2*a)*a);
17 return 0;
18 }
[motoki@x205a]$ gcc rectangular-parallelepiped.c [motoki@x205a]$ ./a.out
厚紙の縦 = ? 38 厚紙の横 = ? 57
切り取る正方形の一辺 = ? 8
==> 直方体の体積 = 7216 立方cm [motoki@x205a]$
ここで、
• プログラムの1〜3行目 は注釈。
• プログラムの8行目 は、int型データを格納するための領域を3つ確保し、それぞれ x, y, a と名付けることをコンパイラに知らせる宣言文である。
• プログラムの9行目,11行目,13行目 はデータの入力を促す文字列(プロンプトと呼ぶ) を出力している部分である。続く10行目,12行目,14行目 で、各々のプロンプトに対 するデータ入力が行われる。
• プログラムの15〜16行目 は、書式付き出力の関数 printfを呼び出している。これに より、結局次のような出力がなされる。
空行
==> 直方体の体積 = 第2引数で指定された式 (x-2*a)*(y-2*a)*a の値 立方cm ここで注目すべき点は次の通りである。
3 C言語の printf 関数においては、出力データを算術式で指定することができる。
'
&
$
% 補足:一般に、プログラムの中でコンピュータの基本動作に相当する部分を文
(state-ment)と呼ぶ。特にC言語においては、セミコロン(;) は文の終わりを表す記
号である。
C言語においては、等号=は+や *と同じ様に演算子(operator)に分類され、
代入演算子と呼ばれる。 そして、変数=式 というもの自身が値をもつ式とし て扱われる。 [変数に値が格納されるのは単なる副作用と考える。]
□演習 5.8 (整数の商) 9桁以下の2つの正整数 m, n を入力して、
m
nの小数部を切捨てて得られる整数値 を出力するプログラムを作成せよ。
□演習 5.9 (四捨五入) 9桁以下の2つの正整数 m, n を入力して、
m
nの小数部を四捨五入して得られる整数値 を出力するプログラムを作成せよ。'
&
$
% Hint:
このプログラムは、例えば m= 7, n= 3なら2 を、m= 8, n= 3なら3 を出 力することになる。 そのために、実際にはプログラム内で
m n +1
2
=
2m+n 2n
=
m+⌊n/2⌋ n
の計算をint型算術式で表せばよい。 ここで、⌊x⌋はxを越えない最大整数を 表す。
float型だと、有効桁が少ないために、入力値が大きい時に正確な数値が出力さ
れないことがある。
□演習 5.10 (時間→秒) 3つの非負整数 h, m, s を入力して、h時間m分s秒に相当す る時間の長さを秒単位に変換して出力するCプログラムを作成せよ。