前回の内容 標準 I/O printf と scanf の秘密 printf -- 今までは、「文字列の出力」関数 書式付きで、色々なデータが表示できる、便利関数 %d 整数値 %f 浮動小数点数 %c 文字 %s 文字列 scanf -- printf と対を成して、入力を行う関数 入力する値の型を示す書式を最初の引数として、指定 その後に、入力をした値を保存する変数名の前に「&」を付けたものを並べる %d 整数値 %lf 浮動小数点数 %c 文字 %s 文字列 ( <= これの使い方は後日 ) リダイレクション 入力や出力を keyboard や display でなく、ファイルに向ける事ができる コマンドラインに < (入力), > (出力) を指定して、 入力や出力の行き先を変更(リダイレクション)できる 出力をファイルにリダイレクションすると、 プログラムの出力を簡単にファイルに保存できる 入力をファイルからリダイレクションすると、 同じ入力を何度もしなくてもすむ 概念 入力や出力が、C 言語の世界では、 抽象化されている C のプログラムでは、 printf が「標準出力」を対象に出力を行う 「標準出力」が何かは、C 言語は気にしない ubuntu が display (標準) / リダイレクションしてファイルする のように「標準出力」の行き先を(プログラムと無関係に)決められる == while 構文 概念 : 繰返しのため構文 同じ命令を繰り返す事ができる ( cf. 再帰呼出し ) 表現 : while 構文 while (「繰り返し条件」) { 「繰り返す命令」 } 「条件」の部分は、if と同じ 「繰り返す命令」の中には、「代入」が必須 (でないと「条件」が変化しない) 振る舞い while ( Q ) { C; } 0) まず Q をチェック ( 成立するかどうかを判定 ) 1) Q が不成立なら、終わり 2) C を実行する 3) 再び 0 に戻る # Q をチェックする回数は C を実行する回数より 1 だけ多い 実際に C を何度も繰り返したいのであれば、 a) while 構文の前に Q が成立するように仕向ける b) C を何度か実行すると、いつかは Q が不成立になるようにする => そうしないと、無限 Loop になる while 構文では、繰り返したい命令を C の所に直接書く -> 直観的 ( 再帰に比較して.. ) while 構文を適切に終了させるためには、 代入文が必要 while 構文 vs 再帰 while 構文は、簡単に再帰に変換できる <<変換規則>> func() { while (条件) { 文 } } → func() { if (条件) { 文; func(); } else {} } ( 実は原理的に逆も可能だが自明ではない ) !! 再帰の構造が複雑になると、 !! それと同じ機能を while 構文で実現するのは、結構熟練が必要 その意味で、再帰の方が「表現力」がある(優秀)といえる 逆に(工学のトレードオフの典型例)、 while 構文の方が「効率」がよい !! => 変数と代入が機能の実現時に効率が良い !! !! 変数に保存されている値(計算結果)を再利用できる !! !! <= 同じ計算を何度もしなくて済む == while 構文の考え方(観点) # vs 再帰 # 「再帰」 => 再帰的に定義されている関数を(自然に..)表現する方法 # 1 (n <= 0) # 例 : fact(n) = n! = { # n * ((n-1)!) (n > 0) # 再帰を利用すると、繰り返しが実現される # fact の例では、掛け算と引き算が繰り返される # => 明示的ではない => 繰り返しの対象が明示されている そこには、「代入文」が必要 <= 代入は、「時間の概念」 while 構文は、「時間を進めている..」 等差数列 {a_n} : 初項が 1 で、公差が 3 の数列 a_0 = 1 a_{n} = a_{n-1} + 3 再帰版の場合の計算の仕組み a_n => a_{n-1} を計算 => a_{n-2} を計算.. .. a_0 を計算 <= 初項なので 1 が返る <= a_0 の値から 3 を加えて a_1 を求め、それを返す .. <= a_{n-1} の値が計算できて、返ってくる <= a_n が計算できる # 関数を定義する # => 関数を呼び出すと、計算が進む while 構文 いきなり、a_0 を求める ( 初項なので 1 になる ) a_0 を利用して a_1 を計算する ... a_n を計算する # 計算の手順を明示、時間(代入)を進める 変数の値を代入によって、書き換える事を繰り返して 最終的な目標(例:計算結果)を得る手順を記述する => 手続き型言語 == while 構文を活用して、だんだんと時間を進めて、計算を行う 数値計算をしてみたい 具体例 関数 y = f(x) は、区間 [a,b] で、連続関数として、 f(a) f(b) < 0 => 中間値の定理より、 区間 [a,b] 内に、f(c)=0 となる c が存在する この c は、方程式 f(x)=0 の区間 [a,b] 内の解になっている 考え方 ( 解析的な考え方 : 微分積分学の立場 ) まず、適当に解の候補を考え、それを、求める解に近づけてゆく 十分に近くなったら、(誤差を含んでいるが..) それを答えとみなす。 # cf. 代数的な考え方 # 手順にした違って、処理をすると、 # 直接答えが得られる ( 近似ではない場合もある ) 二分法 最初に、答えがその中にあると思われる区間 [a,b] を考え、 その区間を、「その中に答えがあるという状態を維持しつつ」 その区間を縮めてゆく while ( 区間が(まだ)広い ) { 区間を縮める => 区間を半分にして、そのどちらかを選ぶ } while 構文の考え方 答の候補を作る ( そんなに、精度がよくなくてもよい ) 答の候補が十分に答えに近くなるまで、 答えを修正する while ( 答えの候補の精度が不十分 ) { 答えを改良する }