この文書の URL は http://www.cc.kyoto-su.ac.jp/~mtkg/lecture/comp_B/2012/10.html です。
四則演算
加減乗除を試してみましょう。
割り算(商を求める演算子)は /
です。
ファイル名を work1001.c
として次のプログラムを作成してみましょう。
/* work1001.c 加減乗除 */ #include <stdio.h> int main(void) { int nx, ny; printf("Inputs two integers: "); scanf("%d %d", &nx, &ny); /* & を忘れないように */ printf("nx + ny = %d\n", nx + ny); printf("nx - ny = %d\n", nx - ny); printf("nx * ny = %d\n", nx * ny); printf("nx / ny = %d\n", nx / ny); return 0; }
プログラムを実行すると入力待ちの状態になります。
24 と 5 を空白で区切って入力しリターンキーを押すと、scanf 関数で指定した順番にしたがって
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つの整数を読み込んで平均値を表示するプログラムを作成してみましょう。
ファイル名は work1002.c
とします。
/* work1002.c 平均の計算 */ #include <stdio.h> int main(void) { int nx, ny; printf("Inputs two integers: "); scanf("%d %d", &nx, &ny); printf("mean = %d\n", (nx + ny) / 2); return 0; }
計算の優先順序
nx + ny
を ( )
で囲んで正しい順序で計算されるようにします。
C では通常の演算規則と同じように演算の優先順序が決められています。
結果の型
いくつか試してみましょう。
% ./a.out Inputs two integers: 10 12 mean = 11 % ./a.out Inputs two integers: 10 13 mean = 11
10 と 12 の平均は正しく計算できていますが、10 と 13 の結果は変ですね。 C では「整数 / 整数」の結果が整数になり、結果の小数部分が切り捨てられるので、このような結果になります。 平均を正しく計算するには次の「double 型」を使います。
double 型
C では実数を「浮動小数点数」 (floating point number) という形式で表します。 浮動小数点数には精度の異なるいくつかの種類がありますが、一般的には「double 型」が使われます。 (C の double 型は Fortran 90/95 の real(8) 型に相当するものです。)
double 型は次の範囲の実数を近似的に表すことができます。
(ここで 10^n
は 10 の n 乗を表すものとします。)
- 最小値:
±2.225073858507201×10^(-308)
- 最大値:
±1.797693134862316×10^(+308)
- 精度: 10進数で約14桁 (2進数で53桁)
整数型と実数型の性質の違いをみるために、次のようなプログラムを作成してみましょう。
ファイル名は work1003.c
とします。
printf 関数で実数型の変数を表示するには %f
という書式を使います。
/* work1003.c */ #include <stdio.h> int main(void) { int nx; double dx; nx = 9.99; /* int 型に実数を代入 */ dx = 9.99; /* double 型に実数を代入 */ printf("nx = %d\n", nx); /* int 型を表示する場合は %d */ printf("dx = %f\n", dx); /* double 型を表示する場合は %f */ printf("nx / 2 = %d\n", nx / 2); printf("dx / 2 = %f\n", dx / 2); return 0; }
これを実行すると次のようになります。
% ./a.out nx = 9 dx = 9.990000 nx / 2 = 4 dx / 2 = 4.995000
この結果から次のことがわかります。
- int 型の変数
nx
に実数 9.99 を代入すると、小数部分が切り捨てられnx
には 9 が格納される。 nx / 2
の計算では結果が int 型になり、小数部分が切り捨てられる。dx / 2
の計算では結果が int 型になり、小数部分の切り捨ては行われない。
型と演算
C では、演算を構成している定数や変数の型がすべて同じ場合は、結果も同じ型になります。 例えば、「int / int」の結果は int 型、「double / double」の結果は double 型になります。
一方、「double / int」や「int / double」のように演算の対象が異なる型の場合は、int 型が double 型に変換されてから演算が行われます。 これを「暗黙の型変換」といいます。 例えば、「5.0 / 2」という演算では int 型の整数 2 が double 型の実数 2.0 に変換されてから割り算が行われます。
こうした規則は割り算 /
だけでなく +
や -
, *
にも同様に適用されます。
定数の型
double 型の定数は「10 を基数とする指数表現」を使って次のように表すことができます。
実数定数 意味 値 ----------------------------------------------------------------- 3.14e+0 3.14 x 10^0 3.14 1.25e+3 1.25 x 10^3 1250.0 0.8e-3 0.8 x 10^(-3) 0.0008
Fortran の real(8) 型では 3.14d+0
でしたが、C では 3.14e+0
と書きます。
間違えないように注意しましょう。
平均値の計算 (2)
2つの整数を読み込んで平均値を「正しく」計算するプログラムを作成してみましょう。
ファイル名は work1004.c
とします。
/* work1004.c */ #include <stdio.h> int main(void) { int nx, ny; printf("Input two integers: "); scanf("%d %d", &nx, &ny); printf("mean = %f\n", (nx + ny) / 2.0); return 0; }
実際に行われる計算
平均を求める式 (nx + ny) / 2.0
に注目してみましょう。
work1002.c
との違いは 2
が 2.0
になっただけです。
計算機の中で行われる計算は次のようになります。
nx + ny
は int 型同士の演算です。したがって、この加算の結果は int 型になります。(nx + ny) / 2.0
は「int / double」という演算になります。 したがって、int 型が double 型に変換されてから割り算が実行され、最終的な結果は double 型になります。
C プログラミングでは常に「型」を意識することが大切です。
型変換
明示的な型変換(キャスト)を使って整数型の定数や変数を実数型に変換することができます。 キャストには変換したい型名を括弧でくくり、変数の前に置きます。
したがって、平均を求める式は次のように書くこともできます。
(double) (nx + ny) / 2;
この場合は nx + ny
の結果(int 型)が double 型に変換され、「double 型 / 2」の計算が行われます。
したがって、int 型の定数 2 は自動的に double 型の 2.0 に変換され、演算の結果は double 型になります。
キャストによる型変換は一時的なもので、nx や ny の型が int であることに変わりはありません。
同様に、double 型を int 型にキャストすることもできます。 この場合は小数部分の切り捨てが行われます。
int i; double x; x = 1.8; i = (int) x; /* i は 1 になる。キャストしなくても結果は同じ(暗黙の型変換) */
符号の反転
値の符号を反転させるには -
演算子を使います。
キーボードから実数を読み込み、符号を反転させて表示するプログラムは次のようになります。
/* work1005 */ #include <stdio.h> int main(void) { double dx; printf("Inputs a real: "); scanf("%lf", &dx); /* scanf では %lf */ printf("-dx = %f\n", -dx); /* printf では %f */ return 0; }
符号を変化させない +
演算子もありますが、ほとんど使われません。
double 型の書式
double 型の実数をキーボードから読み込む場合、scanf 関数に与える書式は
%lf
とします。
printf 関数に与える書式 %f
と間違えないように注意しましょう。
剰余
2つの整数を読み込んで、その商と剰余(割り算の余り)を表示してみましょう。 C では int 型の整数 a を整数 b で割った余りを
a % b
で計算することができます。
/* work1006 */ #include <stdio.h> int main(void) { int nx, ny; printf("Input two integers: "); scanf("%d %d", &nx, &ny); printf("%d / %d = %d\n", nx, ny, nx / ny); printf("%d %% %d = %d\n", nx, ny, nx % ny); return 0; }
正しく計算できるか確かめてみましょう。
% ./a.out Input two integers: 27 6 27 / 6 = 4 27 % 6 = 3
printf で %
を表示する
書式文字列中に %%
と書くと画面に %
が表示されます。
練習問題
剰余を %
を使わないで計算せよ。
printf("mod2 = %d\n", nx - (nx / ny) * ny);
本日の課題
1. 明示的な型変換
明示的な型変換(キャスト)を利用して、キーボードから読み込んだ実数の小数部分を求めるプログラムを作成せよ。 ある実数の小数部分を求めるには整数部分を引けばよい。 次のようにキャストすれば double 型変数 x の整数部分が得られる。
(int) x;
2. 相加平均と相乗平均
2つの実数を読み込んで、相加平均と相乗平均を計算するプログラムを作成せよ。
相乗平均の計算には平方根を計算する sqrt(double 型)
という関数を利用する。
注意:
sqrt()
, sin()
, cos()
, tan()
などの「数学関数」を利用する場合は、プログラムの冒頭に
#include <math.h>
を追加すること。
また、コンパイル時に -lm
オプションが必要になることもある。
これは libm.a というライブラリ(いろいろな関数を集めたもの)をリンクせよという意味である。
-lfoo
は libfoo.a をリンクするという意味になる(foo にはいろいろな文字列が入る)。
Linux では多くのライブラリが /usr/lib
ディレクトリに集められており、コンパイラ(正確にはリンカ)はデフォルトで /usr/lib
, /usr/local/lib
などにあるライブラリを検索する。
% gcc work1008.c -lm
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
立方根の計算にはべき乗を計算する関数 pow(x, y) を利用する。 引数 x, y はともに double 型で pow(x, y) は x の y 乗を返す。 したがって、double 型の変数 dx, dy, dz の積の立方根(1/3 乗)を計算するには
pow(dx * dy * dz, 1.0/3)
とすればよい。
チャレンジ問題
1. 和と平均
ナシ、リンゴ、ミカンの値段を入力し、合計と平均を表示するプログラムを作成せよ。
2. 消費税
鉛筆の値段(税抜き)を1本80円とする。 鉛筆の本数を入力し、消費税込みの合計金額を表示するプログラムを作成せよ。 消費税は 5% とする。
3. 西暦→平成
西暦年を入力し平成年を表示するプログラムを作成せよ。 結果がマイナスになっても構わない。
4. 時間の変換
秒数を入力し、時間・分・秒に変換するプログラムを作成せよ。 (例:4000秒 → 1時間6分40秒)
5. おつりの計算
買い物をして1万円札を出したとき、お釣りの札と硬貨の枚数を、札と硬貨の枚数の合計が最小になるように決めるプログラムを作成せよ。