数値計算と誤差 (1)
今日の内容
- C 言語で書かれたプログラムの動かし方
- 数値計算での変な現象
- 誤差について知る
C 言語で書かれたプログラムの動かし方
3つの数の最大公約数を求めるプログラム
/* gcd.c
3つの整数の最大公約数を求めるプログラム */
#include <stdio.h>
int gcd(int x, int y) {
int r;
r = x % y;
while (r > 0) {
x = y;
y = r;
r = x % y;
}
return y;
}
int main(void) {
int s, t, u;
scanf("%d", &s);
scanf("%d", &t);
scanf("%d", &u);
printf("%d\n", gcd(gcd(s, t), u));
}
- このプログラムを実行するのには,以下のように cc コマンドを使ってコンパイル (機械語に翻訳変換する作業) を行う.
- コンパイルをすると a.exe というコンピュータで直接実行できる機械語のファイルが出来るので,それを実行する.
# cc gcd.c
# ./a.exe
12
8
40
4
#
[演習 13.1]
- C 言語のプログラムを保存するために,ディレクトリ c を mkdir で作りなさい.
- ディレクトリ c に移動し,上の C 言語のプログラムをファイル gcd.c にエディタを使って書き,保存しなさい.
- プログラムを実行しなさい.
数値計算での変な現象
- プログラミング言語 Ruby では非常に大きな整数を扱えるが,それは Ruby の処理系内で対応しているためで,CPU そのものの機能ではない.
Ruby 以外の多くのプログラミング言語では CPU に忠実に計算を行っている.
- C 言語はコンパイル型のプログラミング言語なので,コンパイル (翻訳) という作業が必要になる.
整数の計算での変な現象 (オーバーフロー)
/* int_overflow.c
整数計算での変な現象 */
#include <stdio.h> // 入出力のライブラリを使う宣言
int main(void) { // C 言語は関数 main から実行が始まる.
int i; // int で変数 i が整数型であることを示す.
i = 1; // 文の区切りを ; で表す.
while (i > 0) {
i = i + 1;
}
printf("%d \n", i); /* 関数 printf の第1引数は,文字列で出力の形式を表す.
%d は10進数による数の表現.
\n は改行を表す.
第2引数以後は,%d などで表示される変数を現れる順番に記述する.*/
}
# cc int_overflow.c
# ./a.exe
-2147483648
#
[演習 13.2]
- プログラムを実行しなさい.
- 1から1ずつ大きくしたのに何故負の数になってしまうのだろうか?
[問題 13.1]
- CPU で表現できる最小の整数と最大の整数を表示するプログラムを書いて実行しなさい.
- プログラムをメイルで授業時間内に提出すること.
- メイルの件名: CS入門 問題13.1
- メイルの本文に氏名と学籍番号を必ず書くこと.
- プログラムは添付ファイルにすること.
- 東工大のアカウント以外から出されたメイルは受取らない.
誤差
丸め誤差
- 数学では正しい等式だが,プログラムではどうなるか確かめてみよう.
/* round-off_error.c
丸め誤差の例 */
#include <stdio.h>
int main(void) {
double d1 = 1.0 - 0.9;
double d2 = 0.1;
if (d1 == d2) {
printf("d1 is %g and d2 is %g, then d1 == d2 is true.\n", d1, d2);
} else {
printf("d1 is %g and d2 is %g, but d1 == d2 is false.\n", d1, d2);
printf("d1 - d2 = %g\n", d1-d2);
}
}
情報落ち
/* taylor.c
情報落ちの例: log 1.5 の計算 */
#include <stdio.h>
#include <math.h>
int main(void) {
int i, j;
double s, x;
s = 0;
for (i = 1; i <= 100; i++) {
x = i;
for (j = 0; j < i; j++) {
x = x * 2;
}
if (i % 2 == 0) {
s = s - 1/x;
} else {
s = s + 1/x;
}
}
printf("%.20f\n", s);
}
[問題 13.3]
- 演習 13.3 の結果を信用できるか?
- テイラー展開を1項目から100項目まで順に足すのでなく,100項目から1項目まで足したらどうなるか?
桁落ち
[問題 13.4]
- x2 - 1000.001 x + 1 = 0 をプログラムで解きなさい.
因数分解による解は -1000 と -0.001 である.
$ ./a.exe
a=1.0000000000000000e+00
b=1.0000010000000000e+03
c=1.0000000000000000e+00
x1=-9.9999999997635314e-04
x2=-1.0000000000000000e+03
$
次回の予告
- 次回の授業は教室で行います.
- 教科書を使いますので忘れずに持って来て下さい.
- 来週の授業の主な内容 (予定)
2013年1月7日作成
2013年1月10日修正
伊知地 宏
Copyright (C) Hiroshi Ichiji, 2013. All rights reserved.