Download : sample-001.c
/*
* 2020/10/16 sample-001.c
*/
/*
* 複数条件の分岐
*
* 利用方法
* コンパイル
* cc -I ~/c/include -o sample-001.exe sample-001.c
* 実行
* sample-001
*/
#include <stdio.h>
/*
* trump
* トランプの番号から、その名前を表示する
*/
void trump ( int number ) {
printf ( "数値 %d の表すカードは、", number );
if ( number == 1 ) { /* 番号が 1 なら エース (A) */
printf ( "エース" );
} else if ( number == 11 ) { /* 番号が 11 なら ジャック (J) */
printf ( "ジャック" );
} else if ( number == 12 ) { /* 番号が 12 なら クイーン (Q) */
printf ( "クイーン" );
} else if ( number == 13 ) { /* 番号が 13 なら キング (K) */
printf ( "キング" );
} else if ( number == 0 ) { /* 番号が 0 の場合は例外的に ジョーカー ($) */
printf ( "ジョーカー" );
} else { /* それ以外 */
if ( number < 0 ) { /* 番号が負の場合は.. */
printf ( "範囲外" );
} else if ( 13 < number ) { /* 番号が 13 より大きい場合は.. */
printf ( "範囲外" );
} else { /* それ以外は.. */
printf ( "%d の数カード", number );
}
}
printf ( "です。\n" );
}
/*
* main
*
*/
int main( int argc, char *argv[] )
{
trump ( -1 );
trump ( 0 );
trump ( 1 );
trump ( 7 );
trump ( 10 );
trump ( 13 );
trump ( 20 );
return 0;
}
$ ./sample-001.exe 数値 -1 の表すカードは、範囲外です。 数値 0 の表すカードは、ジョーカーです。 数値 1 の表すカードは、エースです。 数値 7 の表すカードは、7 の数カードです。 数値 10 の表すカードは、10 の数カードです。 数値 13 の表すカードは、キングです。 数値 20 の表すカードは、範囲外です。 $
Download : sample-002.c
/*
* 2020/10/16 sample-002.c
*/
/*
* 複数条件の分岐(case 文を利用した場合)
*
* 利用方法
* コンパイル
* cc -I ~/c/include -o sample-002.exe sample-002.c
* 実行
* sample-002
*/
#include <stdio.h>
/*
* trump
* トランプの番号から、その名前を表示する
*/
void trump ( int number ) {
printf ( "数値 %d の表すカードは、", number );
switch ( number ) { /* 一つの式の値で分岐 */
case 1: /* 番号が 1 なら エース (A) { (開きブロック) */
printf ( "エース" );
break; /* ここで 1 の場合がおわる } (閉じブロック) */
case 11: /* 番号が 11 なら ジャック (J) */
printf ( "ジャック" );
break;
case 12: /* 番号が 12 なら クイーン (Q) */
printf ( "クイーン" );
break;
case 13: /* 番号が 13 なら キング (K) */
printf ( "キング" );
break;
case 0: /* 番号が 0 の場合は例外的に ジョーカー ($) */
printf ( "ジョーカー" );
break;
case 2: /* 範囲は指定できないので、全て列挙 */
/* 2 の場合は 3 の場合と同じなので break しない */
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
printf ( "%d の数カード", number );
break; /* 2 〜 10 の場合はここで、終了 */
default: /* それ以外は.. */
printf ( "範囲外" );
break; /* これは不要だが、つける習慣を (マナー) */
}
printf ( "です。\n" );
}
/*
* main
*
*/
int main( int argc, char *argv[] )
{
trump ( -1 );
trump ( 0 );
trump ( 1 );
trump ( 7 );
trump ( 10 );
trump ( 13 );
trump ( 20 );
return 0;
}
$ ./sample-002.exe 数値 -1 の表すカードは、範囲外です。 数値 0 の表すカードは、ジョーカーです。 数値 1 の表すカードは、エースです。 数値 7 の表すカードは、7 の数カードです。 数値 10 の表すカードは、10 の数カードです。 数値 13 の表すカードは、キングです。 数値 20 の表すカードは、範囲外です。 $
Download : sample-003.c
/*
* 2020/10/16 sample-003.c
*/
#include <stdio.h>
/*
* for 文を利用して、0 から 9 の数値を表示する
*
* 利用方法
* コンパイル
* cc -I ~/c/include -o sample-003.exe sample-003.c
* 実行
* sample-003
*/
int main(int ac, char *av[] ) {
int i; /* for 文の制御変数 */
for ( i = 0; i < 10; i = i + 1 ) {/* i を 0 〜 9 迄変化 */
printf ( "%d\n", i ); /* i を出力 */
}
return 0;
}
$ ./sample-003.exe 0 1 2 3 4 5 6 7 8 9 $
Download : sample-004.c
/*
* 2020/10/16 sample-004.c
*/
#include <stdio.h>
/*
* for 文を利用して、1 から 10 の数値を表示する
*
* 利用方法
* コンパイル
* cc -I ~/c/include -o sample-004.exe sample-004.c
* 実行
* sample-004
*/
int main(int ac, char *av[] ) {
int i; /* for 文の制御変数 */
for ( i = 1; i <= 10; i = i + 1 ) {/* i を 1 〜 10迄変化 */
printf ( "%d\n", i ); /* i を出力 */
}
return 0;
}
$ ./sample-004.exe 1 2 3 4 5 6 7 8 9 10 $
Download : sample-005.c
/*
* 2020/10/16 sample-005.c
*/
#include <stdio.h>
/*
* for 文を利用して、0 から 9 の数値を表示する
*
* 利用方法
* コンパイル
* cc -I ~/c/include -o sample-005.exe sample-005.c
* 実行
* sample-005
*/
int main(int ac, char *av[] ) {
int i; /* for 文の制御変数 */
for ( i = 0; i < 10; i++ ) { /* i を 0 〜 9 迄変化 */
/* i++ は i = i + 1 と同じ */
printf ( "%d\n", i ); /* i を出力 */
}
return 0;
}
$ ./sample-005.exe 0 1 2 3 4 5 6 7 8 9 $
Download : sample-006.c
/*
* 2020/10/16 sample-006.c
*/
#include <stdio.h>
/*
* for 文を利用して、0 から 9 迄の 10 個の数値を和を表示する
* sum = \sum_{i=0}^{9} i
*
* 利用方法
* コンパイル
* cc -I ~/c/include -o sample-006.exe sample-006.c
* 実行
* sample-006
*/
int main(int ac, char *av[] ) {
int i; /* for 文の制御変数 */
int sum = 0;
for ( i = 0; i < 10; i++ ) { /* i を 0 〜 9 迄変化 */
/* i++ は i = i + 1 と同じ */
sum = sum + i; /* sum に i の値を加える */
printf ( "%d %d\n", i, sum ); /* i と sum を出力 */
}
printf ( "最終的には sum = %d\n", sum );
return 0;
}
$ ./sample-006.exe 0 0 1 1 2 3 3 6 4 10 5 15 6 21 7 28 8 36 9 45 最終的には sum = 45 $
Download : sample-007.c
/*
* 2020/10/16 sample-007.c
*/
#include <stdio.h>
/*
* for 文を利用して、0 から 9 の数値を表示する
* プログラムを while に書き直す
*
* 利用方法
* コンパイル
* cc -I ~/c/include -o sample-007.exe sample-007.c
* 実行
* sample-007
*/
int main(int ac, char *av[] ) {
int i; /* for 文の制御変数 */
/* 元々のプログラム
for ( i = 0; i < 10; i++ ) {
printf ( "%d\n", i );
}
step-1
<初期化式> を前にもってくる
i = 0;
for ( i < 10; i++ ) {
printf ( "%d\n", i );
}
step-2
<再初期化式> を、繰返し文の後にもって行く
i = 0;
for ( i < 10 ) {
printf ( "%d\n", i );
i++; <= { 〜 } の一番最後
}
step-3
for を while に書き換える
i = 0;
while ( i < 10 ) {
printf ( "%d\n", i );
i++;
}
*/
/* 元々のプログラム
for ( i = 0; i < 10; i++ ) {
printf ( "%d\n", i );
}
*/
i = 0;
while ( i < 10 ) {
printf ( "%d\n", i );
i++;
}
return 0;
}
$ ./sample-007.exe 0 1 2 3 4 5 6 7 8 9 $
Download : sample-008.c
/*
* 2020/10/16 sample-008.c
*/
#include <stdio.h>
/*
* for 文では、条件式がサボれる
*
* 利用方法
* コンパイル
* cc -I ~/c/include -o sample-008.exe sample-008.c
* 実行
* sample-008
*/
int main(int ac, char *av[] ) {
for ( ;; ) {
/* while では条件を省略できないが for 文ではできる .. */
/* 条件が省略されると、「常に真」になるので無限ループ */
/* プログラムを停止させるには
* Ctrl-C ([Ctrl] キーを押しながら [C] キーを押す)
* を押す。
*/
printf ( "動いています...\n" );
}
return 0;
}
動いています... 動いています... 動いています... 動いています... .... 動いています... 動いています... 動いています... 動いています... 動いてい^C
Download : sample-009.c
/*
* 2020/10/16 sample-009.c
*/
#include <stdio.h>
/*
* for 文を利用して、0 から 99 の偶数の数値
* アプローチ
* (その一) i を 0 〜 99 として、但し偶数だけを出す
*
* 利用方法
* コンパイル
* cc -I ~/c/include -o sample-009.exe sample-009.c
* 実行
* sample-009
*/
int main(int ac, char *av[] ) {
int i; /* for 文の制御変数 */
for ( i = 0; i < 100; i++ ) { /* i を 0 〜 99 迄変化 */
/* 但し、i が偶数の時だけ → if 文を利用する */
if ( i % 2 == 0 ) { /* i を 2 で割った余り(i%2)が 0 */
/* 即ち i が偶数の時.. */
printf ( "%d\n", i ); /* i を出力 */
}
}
return 0;
}
$ ./sample-009.exe 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 $
/*
* 課題 CNAME-02
*
* 20201016 20201016-02-QQQQ.c
*
* 0 〜 99 の偶数を出力する
*
*/
#include <stdio.h>
/*
* for 文を利用して、0 から 99 の偶数の数値
(そのニ) i が 0 〜 99 の間の偶数だけを動くようにし、毎回 i を出す
0, 2, 4, ..
^^^
+2
*/
int main(int ac, char *av[] ) {
int i; /* for 文の制御変数 */
for ( i = 0; i < 100; i = i + 2 ) {
/* i++ だと i = 0, 1, 2, .. */
/* ○○とすれば i = 0, 2, 4, .. */
printf ( "%d\n", i ); /* i を出力 */
}
return 0;
}
/*
* 課題 CNAME-02
*
* 20201016 20201016-02-QQQQ.c
*
* 0 〜 99 の偶数を出力する
*
*/
#include <stdio.h>
/*
* for 文を利用して、0 から 99 の偶数の数値
(その一)
0 ? 99 の数値 : 100 個
偶数は、100/2 = 50
=> 50 個出力する
*/
int main(int ac, char *av[] ) {
int i; /* for 文の制御変数 */
for ( i = 0; i < 50; i++ ) {
/* i = 0, 1, 2, .., 49 */
/* 2*i = 0, 2, 4, .., 98 */
printf ( "%d\n", 2*i ); /* 2*i を出力 */
}
return 0;
}
#include <stdio.h>
/*
階乗の計算 (帰納的の定義)
1 ( n = 0 / n = 1 )
n! = {
n * (n-1)! ( n > 1 )
3! = 3 * (3-1)!
= 3 * 2!
= 3 * ( 2 * (2-1)! )
= 3 * ( 2 * 1! )
= 3 * ( 2 * ( 1 ) )
= 3 * 2 * 1
= 6
*/
/* 階乗の計算の再帰版
* 数学の帰納的に定義された関数定義を、
* そのまま C 言語の関数再帰的定義
* で表現できる
*/
int fac ( int n ) {
if ( n > 1 ) { /* n > 1 の時 */
return n * fac ( n - 1 ); /* n! = n * (n-1)! */
/* fac(n) = n * fac(n-1) */
} else { /* n <= 1 ( n = 1, 0 ) */
return 1; /* fac(1) = 1 */
}
}
int main(void) {
printf ( "3! = %d\n", fac(3) );
printf ( "6! = %d\n", fac(6) );
return 0;
}
#include <stdio.h>
/*
階乗の計算 (帰納的の定義)
1 ( n = 0 / n = 1 )
n! = {
n * (n-1)! ( n > 1 )
3! = 3 * (3-1)!
= 3 * 2!
= 3 * ( 2 * (2-1)! )
= 3 * ( 2 * 1! )
= 3 * ( 2 * ( 1 ) )
= 3 * 2 * 1
= 6
*/
/* 階乗の計算の繰り返し (while 構文)
* n! を計算するには、1 から n まで、の自然数を順に掛け算する
* 1
* 1 * 2
* 1 * 2 * 3
* ...
* 1 * 2 * ... * n
* 「* k 」を何度も繰り返す
*/
int fac ( int n ) {
int result = 1; /* 最終的な答え(階乗の計算結果)を保持する変数 */
/* 最初は result = 1 にしておいて、
これに、順に n, n - 1, n - 2, .. をかけてゆく */
printf ( "Start: n = %d, result = %d\n", n, result );
while ( n > 1 ) { /* n > 1 の時 */
printf ( "Pre: n = %d, result = %d\n", n, result );
result = result * n;
n = n - 1;
printf ( "Post: n = %d, result = %d\n", n, result );
}
printf ( "Result: n = %d, result = %d\n", n, result );
return result;
}
int main(void) {
printf ( "3! = %d\n", fac(3) );
printf ( "6! = %d\n", fac(6) );
return 0;
}
#include <stdio.h>
/*
ユークリッドの互助法で
二つの自然数(0 を含む) m,n の最大公約数 (m,n) を求める
(m,0) = m
(m,n) = (n,m % n)
m ( n = 0 の時 )
gcm(m,n) = {
(n,m % n) ( n > 0 の時 )
*/
int gcm ( int m, int n ) {
if ( n > 0 ) {
return gcm ( n, m % n );
} else {
return m;
}
}
int main(void) {
printf ( "gcm(12,18) = %d\n", gcm(12,18) );
printf ( "gcm(111111,111) = %d\n", gcm(111111,111) );
return 0;
}
#include <stdio.h>
/*
ユークリッドの互助法で
二つの自然数(0 を含む) m,n の最大公約数 (m,n) を求める
(m,0) = m
(m,n) = (n,m % n)
m ( n = 0 の時 )
gcm(m,n) = {
gcm(n,m % n) ( n > 0 の時 )
注意 : m % n は m を n で割った余り
*/
int gcm ( int m, int n ) {
int w; /* work (作業用)変数で、変数の値を書き換えるときに */
/* 代入文を利用すると、変数の値が書き変わり、
以前の値が失われるので、それを避けるため使う変数 */
printf ( "(m,n) = (%d,%d)\n", m, n );
while ( n > 0 ) {
/*
gcm(m,n) <= gcm(n,m % n)
m <- n
n <- m % n
*/
w = m; /* 現在の変数 m の値を保存 */
m = n; /* m <- n */
n = w % n; /* w には、上の代入文の前の m の値が入っている */
printf ( "(m,n) = (%d,%d)\n", m, n );
}
return m;
}
int main(void) {
printf ( "gcm(12,18) = %d\n", gcm(12,18) );
printf ( "gcm(111111,111) = %d\n", gcm(111111,111) );
return 0;
}
#include <stdio.h>
/* 階乗の計算の繰り返し (for 構文)
n! = n * (n-1) * .. * 2 * 1
*/
/*
while => for
1) while を for に書き換える
2) while の前に必ず、実行する命令がれば、<初期化式>に書く
3) <継続条件式>はそのまま
4) <繰返し文>の中で、変数を更新しているものを、
<再初期化式>の所に移動
*/
int fac ( int n ) {
int result;
for ( result = 1; n > 1; n = n - 1 ) {
/* for 構文の頭部に、繰り返しに関する情報が集約される */
result = result * n; /* 本体の部分は、主計算の部分だけ */
}
return result;
}
int main(void) {
printf ( "3! = %d\n", fac(3) );
printf ( "6! = %d\n", fac(6) );
return 0;
}
#include <stdio.h>
/* 階乗の計算の繰り返し (for 構文)
n! = n * (n-1) * .. * 2 * 1
*/
/*
for 構文を使った別の例
*/
int fac ( int n ) {
int result = 1;
int i;
for ( i = 1; i <= n; i = i+1 ) {
/* i = 1, (i が一ずつ増える), n ( i = n + 1 になったら終わり ) */
/* <繰返し文> の部分が n 回実行される */
result = result * i;
}
return result;
}
int main(void) {
printf ( "3! = %d\n", fac(3) );
printf ( "6! = %d\n", fac(6) );
return 0;
}
#include <stdio.h>
/*
for 構文の利用例
*/
void nhello ( int n ) {
int i; /* for 構文の制御変数とする */
for ( i = 1; i <= n; i = i + 1 ) {
/* n 回繰り返す */
printf ( "Hello, World\n" );
}
}
int main(void) {
printf ( "Start:\n" );
nhello ( 3 );
printf ( "Middle:\n" );
nhello ( 6 );
printf ( "End:\n" );
return 0;
}
#include <stdio.h>
/*
for 構文の利用例
*/
void nhello ( int n ) {
int i; /* for 構文の制御変数とする */
for ( i = 0; i < n; i = i + 1 ) {
/* n 回繰り返す ( i = 0, 1, .., n - 1 ) */
printf ( "Hello, World\n" );
}
}
int main(void) {
printf ( "Start:\n" );
nhello ( 3 );
printf ( "Middle:\n" );
nhello ( 6 );
printf ( "End:\n" );
return 0;
}
#include <stdio.h>
/*
for 構文の利用例
*/
void nhello ( int n ) {
int i; /* for 構文の制御変数とする */
for ( i = 0; i < n; i++ ) { /* i++ => i = i + 1 と同じ */
/* n 回繰り返す ( i = 0, 1, .., n - 1 ) */
printf ( "Hello, World\n" );
}
}
int main(void) {
printf ( "Start:\n" );
nhello ( 3 );
printf ( "Middle:\n" );
nhello ( 6 );
printf ( "End:\n" );
return 0;
}
#include <stdio.h>
/*
フィボナッチ数
0 ( n = 0 )
fib(n) = { 1 ( n = 1 )
fib(n-1)+fib(n-2) ( n > 1 )
n 0 1 2 3 4 5 6
fib n 0 1 1 2 3 5 8
*/
int fib ( int n ) {
if ( n > 1 ) { /* n > 1 の時 */
return fib(n-1)+fib(n-2); /* fib(n) = fib(n-1)+fib(n-2) */
} else { /* n <= 1 ( n = 1, 0 ) */
return n;
}
}
int main(void) {
printf ( "fib(3) = %d\n", fib(3) );
printf ( "fib(6) = %d\n", fib(6) );
printf ( "fib(40) = %d\n", fib(40) );
return 0;
}
/*
fib(6)
=
fib(6-1)
+
fib(6-2)
=
fib(5)
+
fib(4)
=
fib(5-1)
+
fib(5-2)
+
fib(4-1)
+
fib(4-2)
=
fib(4)
+
fib(3)
+
fib(3)
+
fib(2)
=
fib(3)
fib(2)
fib(2)
fib(1)
fib(2)
fib(1)
fib(1)
fib(0)
=
fib(2)
fib(1)
fib(1)
fib(0)
fib(1)
fib(0)
fib(1)
fib(1)
fib(0)
fib(1)
fib(1)
=
fib(1)
fib(0)
fib(1)
fib(1)
fib(0)
fib(1)
fib(0)
fib(1)
fib(1)
fib(0)
fib(1)
fib(1)
=
1
0
1
1
0
1
0
1
1
0
1
1
= 8
再帰的に定義すると
同じ計算を何度もやることになる
=> 効率が悪い
# 同じ計算をする部分を、意識せずに、関数の定義ができる
# => わかりやすさ ( 無駄を許す事により、単純になって、分かりやすい )
再帰と非再帰は、「どちらかを使う」ではなく、
「両方使う」と考える
最初にプログラムを考えるときには、
(一般的に..) 再帰の方が簡単(考えやすい..)ので、
それでやる
そして、次に効率の事を考えて
(一般的に..) 非再帰の方が効率が良いので、
それに書き換える
=> 最適化を行う
プログラム
正しく動いて、効率が良い事が望ましい
*/
#include <stdio.h>
/*
フィボナッチ数
0 ( n = 0 )
fib(n) = { 1 ( n = 1 )
fib(n-1)+fib(n-2) ( n > 1 )
n 0 1 2 3 4 5 6
fib n 0 1 1 2 3 5 8
*/
int fib ( int n ) {
int i;
int f; /* 今のフィボナッチ数 */
int f1; /* 一つ前 */
int f2; /* 二つ前 */
if ( n < 2 ) {
return n;
} else { /* n >= 2 */
/* 最初 n = 2 の時は */
f2 = 0;
f1 = 1;
for ( i = 2; i <= n; i++ ) {
/* 今のフィボナッチ数の計算 */
f = f1 + f2;
/* 次のは、i が一つ増えるので、f1, f2 の値を更新 */
f2 = f1;
f1 = f; /* 一つ前、二つ前をそれぞれ更新 */
}
}
return f;
}
int main(void) {
printf ( "fib(3) = %d\n", fib(3) );
printf ( "fib(6) = %d\n", fib(6) );
printf ( "fib(40) = %d\n", fib(40) );
return 0;
}
/*
非再帰版(while/for 版)
一度計算した値を変数に保存して、
変数を参照する事により、同じ値を(再度計算せずに..)利用できる
=> 変数に、計算結果を保存し、
その同じ変数を何度も参照することにより、
無駄(同じ値を求める複数の[重複した])計算を省く事ができる
*/
#include <stdio.h>
/*
トランプの番号の表示をしたい
1 ? 13
1 ? 10 数札 => 数値
11 ? 13 役札 =>
11 -> J
12 -> Q
13 -> K
*/
void ptrump( int n ) {
if ( n < 1 ) {
printf ( "?" );
} else if ( 13 < n ) {
printf ( "?" );
} else if ( n < 11 ) {
printf ( "%d", n );
} else if ( n == 11 ) {
printf ( "J" );
} else if ( n == 12 ) {
printf ( "Q" );
} else if ( n == 13 ) {
printf ( "K" );
} /* else {} この状況になることはない */
}
int main(void) {
int n;
for ( n = 0; n < 15; n++ ) {
printf ( "%d : ", n );
ptrump ( n );
printf ( "\n" );
}
return 0;
}
#include <stdio.h>
/*
トランプの番号の表示をしたい
1 ? 13
1 ? 10 数札 => 数値
11 ? 13 役札 =>
11 -> J
12 -> Q
13 -> K
switch 構文版
*/
void ptrump( int n ) {
switch ( n ) { /* 条件の対象が n の値 */
case 1: /* n == 1 の時 */
case 2: /* n == 2 の時 */
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10: /* n == 10 の時 */
printf ( "%d", n );
break; /* いったん処理は終了(switch 構文は終了) */
case 11: /* n == 11 の時 */
printf ( "J" );
break;
case 12:
printf ( "Q" );
break;
case 13:
printf ( "K" );
break;
default: /* 上記以外の値 */
printf ( "?" );
break;
}
}
int main(void) {
int n;
for ( n = 0; n < 15; n++ ) {
printf ( "%d : ", n );
ptrump ( n );
printf ( "\n" );
}
return 0;
}
前回の内容
while 構文
与えられた命令を、繰り返し実行する
関数の再帰的定義をする
while ( 繰り返し条件 ) { 繰り返し命令 }
繰り返し条件 : 変数を含む条件式
繰り返し命令によって、
条件式に含まれる変数の値を変更(代入)して、
(結果として..) いつかは条件が成立しなくなるようにする必要がある
「代入を繰り返す」ための構文
cf. 再帰では、「代入」は(明示的には)現れない
# 目的が実現されるまで、その作業を繰り返しする
# 代入を繰り返し => 変数の値を、目的の値に近づけてゆく
# <= 十分に近い(答えそのものになったら).. 繰り返しを終了
while 構文の応用
数値計算 (解析的発想:答えの近似値の精度を高めて行く)
解析的(厳密に「等号が成立する」=誤差を含まない答えを得る手段)に解けない場合でも、
近似的(誤差を含むかもしれない..)値を得る(数値的に解く)
例: sin(x) = 1 となる x を求めよ、
x = sin^{-1}(1)
二分方法
答えの範囲を半分半分にしてゆき、答えのある場所を探す
範囲は、1/2 になってゆくので、どんどん小さくなるが、
有限回しかできないと、区間の幅が残る
=> 幅 = 誤差
# 数値計算を利用する立場
# 誤差の有り無し、問題の解ける解けないをトレード
# 誤差の大きさ、実行時間のトレード
数値積分
面積を求めるために、一度に求めるのではなく、
少しずつ、加えてゆく ( 求積法 )
# 数学
# ∫_a^b f(x) dx = F(b) - F(a)
while 構文の考え方
変数の値に近似結果を入れ、
それを更新(近似度を高める..)事により、
より、精度の高い(答えに近い)値に変数の値を近づけてゆく
十分に近いなら、終了する ( 繰り返し条件 )
==
for 構文とは
繰返しを記述する構文規則 ( cf. while )
for ( <初期化式>; <継続条件式>; <再初期化式> ) { <繰返し文> }
# cf.
# while ( <継続条件式> ) { <繰返し文> }
初期化式 : 最初に一度だけ、必ず行われる文
継続条件式 : 毎回、繰返し文の実行「前」に評価され
これが偽の場合は終了(<繰り返し文>は実行されない)になる
繰返し文 : for 構文によって繰り返される命令
再初期化式 : <繰り返し文>の実行の「後」に毎回「実行」される
構文の実行状況
while ( <継続条件式> ) { <繰返し文> }
<継続条件式> => 真
<繰返し文>
<継続条件式> => 真
<繰返し文>
..
<継続条件式> => 偽
終了
for ( <初期化式>; <継続条件式>; <再初期化式> ) { <繰返し文> }
<初期化式>
<継続条件式> => 真
<繰返し文>
<再初期化式>
<継続条件式> => 真
<繰返し文>
<再初期化式>
..
<継続条件式> => 偽
終了
for 構文と while 構文は、一方を他方の代わりに使える
for 構文を利用すると、
「繰り返す」ための作業
繰り返し条件に含まれる変数 ( 制御変数 )
にかかわる記述
変数 => 初期化が必要 => <初期化式>
繰り返しなので、(制御変数を含む)条件式 => <継続条件式>
条件を終了させるために => 変数の値の更新 => <再初期化式>
=> for 構文では、
制御変数の処理が、一か所にまとめられるので
(まとめておけば..) 繰り返しの様子が一目でわかる
「繰り返す」作業
の二つを分離できる
インクリメント/デクリメント演算子
変数の値を 1 だけ増やしたり減らしたりする演算子
「++」: 変数を 1 だけ増やす
=> 「i++」 は、「i = i + 1 」と同じと思って良い
「--」: 変数を 1 だけ減らす
=> 「i--」 は、「i = i - 1 」と同じと思って良い
for 構文では、<再初期化式> の所で、よく利用されている
「for ( i = 0; i < n; i++ ) { .. }」は、
「.. を n 回繰り返す」というイデオムになっている
==
「繰り返し」
手段
a) 代入を使わない
関数の再帰的定義
b) 代入を使う
while 構文
for 構文
a) と b) の使い分け
数学的に考えたい
( <= 数学の知識を利用してプログラムを書きたい )
=> 再帰の方がよい (関数型言語的表現)
効率を高めたい / 変数の代入による手続型言語的表現
=> while / for
==
switch 構文
条件分岐 ( if 構文 )
if 構文 => 二分岐 ( 条件が成立 / 不成立 )
switch 構文
=> 一つの式の値が、複数の候補のどれかに一致する
=> 多分岐
=>
if 構文を複雑に組み合わせれば、
(ほぼ) switch 構文と同様な機能が実現です
switch - case 構文
機能
多分岐構文 ( if 文は 2 分岐だが switch は n 分岐 )
構文
<switch 文> ::= switch ( <式> ) { <case 並び> }
<case 並び> ::= <case> の繰返し
<case> ::= <label> : 文並び
<label> := case <定数> | default
※1 一つの <switch 文>内には、同じ <label> を含める事はできない
※2 文並び中に break 文があり、それが実行されると、switch 文は終了する
意味
もし、「式」の値が「定数」の何れかであれば、そのラベル以下の文を実行する
そうでなくて、もし、defualt があれば、そのラベル以下の文を実行する
そのいずれでもなければ、何もしない
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20201016-01.c
/*
* 課題 CNAME-01
*
* CDATE FILENAME
*
* キーボードから一文字入力し、その文字によって異る国の挨拶をする
*/
#include <stdio.h>
/*
* hello ( char contry )
* char contry : 国を表す一文字
* j : 日本
* e : 英語
* c : 中国
* f : フランス語
* g : ドイツ語
*/
void hello ( char cmd ) {
switch ( cmd ) {
case 'j': /* 'j' の時は、日本語にする */
printf ( "こんにちは\n" );
break;
case 'e': /* 'e' の時は、英語にする */
/*
** この部分を完成させなさい
*/
break;
case 'c': /* 'c' の時は、中国語にする */
printf ( "ニイハオ\n" );
/*
** この部分を完成させなさい
*/
case 'f': /* 'f' の時は、フランス語にする */
printf ( "Bonjour\n" );
break;
/*
** この部分を完成させなさい
*/
printf ( "Guten tag\n" );
break;
default: /* どれでもなければ.. */
printf ( "???\n" );
break;
}
}
/*
* main
*/
int main( void )
{
printf ( "国を表す文字を入力してください\n" );
printf ( "\tj\t日本\n" );
printf ( "\te\t英語\n" );
printf ( "\tc\t中国\n" );
printf ( "\tf\tフランス\n" );
printf ( "\tg\tドイツ\n" );
hello ( getchar() ); /* getchar() で文字を入力し、それに対応する結果を出す */
return 0;
}
f
$ ./20201016-01-QQQQ.exe 国を表す文字を入力してください j 日本 e 英語 c 中国 f フランス g ドイツ Bonjour $
Download : 20201016-02.c
/*
* 課題 CNAME-02
*
* 20201016 20201016-02-QQQQ.c
*
* 0 〜 99 の偶数を出力する
*
*/
#include <stdio.h>
/*
* for 文を利用して、0 から 99 の偶数の数値
(そのニ) i が 0 〜 99 の間の偶数だけを動くようにし、毎回 i を出す
*/
int main(int ac, char *av[] ) {
int i; /* for 文の制御変数 */
for ( i = 0; i < 100; /* p:ここ */ ) {
/* i++ だと i = 0, 1, 2, .. */
/* ○○とすれば i = 0, 2, 4, .. */
printf ( "%d\n", i ); /* i を出力 */
}
return 0;
}
$ ./20201016-02-QQQQ.exe 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 $