3. 条件式、 データのバリエーション プログラミング論I 今日の内容 • 条件式を使い,条件に応じた計算を行う – 比較演算 (<,<=,>,>=,=) – 条件式のキーワード: cond, else – 値の性質の判定(奇数,偶数:odd?, even?) – 論理演算 (and, or, not) • データのバリエーションとその区別 – 数値、ブール値、文字列、シンボルおよびその判定 条件式 条件を判断するプログラム • 異なる状況には,異なる方法で処理するプログラム – ゲームプログラム: • 物体の速度や位置はある範囲内か? – エンジン制御プログラム • どういう状況(温度,気圧など)であれば燃料の噴射量 を増減するか? • ある条件の成立を判定して処理する道具立てが必要 – 真(true) または偽(false)の値を持つデータのクラス: • ブール値(Boolean) (または真偽値、真理値) – 条件を評価する式(ブール値を返す) – ブール値(真偽)に依存して異なる値を計算する式 比較演算 - 比較演算子の例 値を比較する演算子: = Scheme式 数式 (= x y) x=y (< x y) x<y (> x y) x>y (<= x y) x ≦ y (>= x y) x ≧ y < > <= >= 意味 x は y と等しい x は y より小さい x は y より大きい x は y 以下 x は y 以上 注意:Schemeでは「≦」,「≧」を使うことはできない – キーボードのキーで入力できない C言語の場合 値を比較する演算子: == Cの条件式 (x == y) (x < y) (x > y) (x <= y) (x >= y) 数式 x=y x<y x>y x≦y x≧y < > <= 意味 x は y と等しい x は y より小さい x は y より大きい x は y 以下 x は y 以上 >= 比較演算の実行例 比較演算の結果値は、条件が成り立てば true, 成り立たなければ false となる 比較演算の実行例 C言語の場合 printf(“%d”,(100==50)); 0 printf(“%d”,(100==100)); 1 printf(“%d”,(5<3)); 0 printf(“%d”,(5<5)); 0 printf(“%d”,(5<7)); 1 比較演算の結果値は、条件が成り立てば 1, 成り立たなければ 0 となる 条件の判断 - 比較演算以外の例 例:奇数か(odd?)、偶数か(even?) • odd? の意味:奇数ならば true (さもなければ false) • even? の意味:偶数ならば true (さもなければ false) ※ 条件を判断する演算子や関数名の末尾は ? を使うことが多い ;; odd?: number -> T/F (define (odd? n) (= (remainder n 2) 1) ) ;; even?: number ->T/F (define (even? n) (= (remainder n 2) 0) ) int odd(int n){ return n%2; } int even(int n){ return (n%2==0); } 論理演算 単純な真偽判定を組合わせ、より複雑な論理的演算を行う. • (and A B) A かつ B A B AかつB AまたはB Aでない 例: (and (= x y) (< y z)) T T • (or A B) A または B 例: (or (= x y) (< x z)) • (not A) Aでない T T F T F F T F F T F T T F F F F T 例: (not (= x y)) 計算例: (and (= 5 5) (< 5 6)) =(and true true) = true (and (= 5 5) (< 5 5)) =(and true false) = false 論理演算(C言語の場合) 単純な真偽判定を組合わせ、より複雑な論理的演算を行う. • (and A B) A かつ B C言語の場合 例: (and (= x y) (< y z)) • (or A B) A または B 例: (or (= x y) (< x z)) • (not A) Aでない 例: (not (= x y)) (x==y)&&(y<z) (x==y)||(y<z) !(x==y) 計算例: (and (= 5 5) (< 5 6)) =(and true true) = true (and (= 5 5) (< 5 5)) =(and true false) = false 条件によって結果を変える式 条件式(Conditional Expression):条件により結果を変える式 例:貯蓄口座~貯蓄残高が高いほど高い利率 (本の4.3節) – $1,000以下の預金に対しては4% – $5,000までの預金に対しては4.5% (define amount 3000) ;; が先に定義されてあると, – $5,000より多額の預金に対しては5%を払う ;; cond式は,0.045を返す 例: ここで amount は預金額の変数 (cond [(<= amount 1000) 0.040] [(<= amount 5000) 0.045] [(> amount 5000) 0.050]) 例 (define amount 3000) ;; amountには、3000という値が割り当てられる (cond [(<= amount 1000) 0.040] ;; (<= 3000 1000) ? → false [(<= amount 5000) 0.045] ;; (<= 3000 5000) ? → true 0.045が返る [(> amount 5000) 0.050]) 条件式 条件式の一般形 (cond (cond [question answer] [question answer] ... または ... [question answer]) [else answer]) ...部分:任意行数のcond行(cond節とも呼ばれる) 各cond行: 条件部(question)と結果部(answer)からなる • 条件部は変数を含む条件述語である; • 結果部は条件述語の成立時に結果を計算する式 条件式の例 (cond [(<= amount 1000) 0.040] ① [(<= amount 5000) 0.045] ② [(> amount 5000) 0.050]) ③ 1つの 大きな式 amount の値によって結果値が変わる 複数の cond節の「条件部」は上から順に判定 • 上の例では①,②,③の順に判定が行われる ①が成り立てば,②,③は判定されない ②が成り立てば,③は判定されない 「条件」の並んだ順序に意味がある 条件の判定順序 (cond 一番上の行の条件 の判定から開始 [(<= amount 1000) [(<= amount 5000) [(> amount 5000) yes no yes no yes 0.040] 0.045] 0.050]) この式でこの判定が no になることはあり得ない→他の書き方もある else の使用例 (cond [(<= amount 1000) 0.040] [(<= amount 5000) 0.045] [else 0.050]) (cond [(<= amount 1000) 0.040] [(<= amount 5000) 0.045] [(> amount 5000) 0.050]) この2つは同じ計算を行う else:「前の条件がどれも成り立たなければ」という意味 (使うときは cond 節 の並びの最後) ★ else を使う方が分かりやすければそうする C言語の場合 (cond [(<= amount 1000) 0.040] [(<= amount 5000) 0.045] [else 0.050]) (cond [(<= amount 1000) 0.040] [(<= amount 5000) 0.045] [(> amount 5000) 0.050]) この2つは同じ計算を行う if (amount<=1000) return 0.040; else if (amount<=5000) return 0.045; else return 0.050; if (amount<=1000) return 0.040; else if (amount<=5000) return 0.045; else if (amount > 5000) return 0.050; 条件の判定順序 (cond 一番上の行の条件 の判定から開始 [(<= amount 1000) [(<= amount 5000) [else yes no yes no 0.040] 0.045] 0.050]) else が評価されると必ずその結果部が選択される 条件式での「条件」として書けるもの 結果が true か false となるもの。例えば: • 比較演算 (<,<=,>,>=,= ) の式 例: (<= amount 1000), (<= amount 5000), (> amount 5000), (= (remainder year 400) 0) • 奇数,偶数のような値の性質判定 例: (odd? k), (number? k) 後述 • trueまたはfalse を結果値とするような関数 例: (is-child? a) • and, or, not を使った条件の組み合わせ 例:(or (= m 1) (= m 2)), (not (= a 0)) など 但し is-child? が例えば次のよう に定義されている こと (define (is-child? age) (< age 12)) 練習 • 福岡市営地下鉄の料 金は距離で決まる。距 離をあらわす変数が distance だとして、 対応する料金を求め る cond 式を書け。 (cond [(<= distance 3) 200] .... ) Scheme式の中では 単位は書かない (暗黙に仮定) 距離 (distance) 料金 3km まで 200円 3km 超7kmまで 250円 7km 超11kmまで 290円 11km 超15kmまで 320円 15km 超19kmまで 340円 19km 超20kmまで 360円 条件式を使った条件関数 利率を求める関数:条件関数(Conditional Function) 先の例預金額を受け取りその金額に対する利率を返す。 → 条件式を用い関数定義を定式化 引数の値によって結果が変わる ⇒ 条件関数と呼ばれる (define (interest-rate (cond [(<= amount 1000) [(<= amount 5000) [(> amount 5000) amount) 0.040] 0.045] 0.050])) amountの 値は 引数として 与えられる このような条件関数はどのようにして開発するか? プログラム設計法:条件関数 条件関数の開発法は? 前述のプログラム設計法を拡張 • Purpose:プログラムの目的を理解、機能の概要を記述 • • Contract, Header, Statement: データ解析(Data Analysis)を導入: – 問題が異なる状況を扱う場合→それらのすべてを識別する必要 • Example:プログラムの振る舞いを「例」で記述. • • 状況ごとに最低でもひとつの関数例 Definition:プログラムの定義を具体化する • 異なる状況の数だけの節をもったcond-式 – 各状況を特徴づける条件を定式化 – 適切な区別:あるcond節の条件がtrue →それ以前の条件はfalse • • 各cond-節に対して関数が何を生成すべきかを決定 Test:検査を通じた誤り(エラー)の発見 条件関数の開発 残高 amount から利率を求める関数 interest-rate – 残高が $1000 以下ならば:利率 4% – 残高が $5000 以下ならば:利率 4.5% – 残高が $5000より多ければ:利率 5% • Purpose ;; interest-rate : number -> number ;; 与えられた金額 amount に対する利率を求める (define (interest-rate amount) ...) • 複数の状況を扱う → 場合分けのためのデータ解析 データ解析 この例での良い方法:数直線上の区間への対応付 利率 0.05 0.045 0.04 0 1000 5000 残高 条件関数の開発:Example 残高 amount から利率を求める関数 interest-rate – 残高が $1000 以下ならば: 利率 4% – 残高が $5000 以下ならば: 利率 4.5% – 残高が $5000より多ければ:利率 5% Example: 状況ごとに少なくともひとつの関数例 (= (interest-rate 1000) .040) (= (interest-rate 5000) .045) (= (interest-rate 8000) .050) 注: 0.040 を .040 と書いても同じ 条件関数の開発:本体式の定義 3つの異なる状況を扱う → 3つの場合を区別するcond節を持つ cond 式 (define (interest-rate (cond [(<= amount 1000) [(<= amount 5000) [(> amount 5000) amount) ...] amount ≦ 1000 のとき ...] 1000<amount≦5000のとき ...] )) 5000 >amount のとき まず3つの条件節内の条件部を考える 条件関数の開発:本体式の定義 3つの異なる状況を扱う → 3つの場合を区別するcond節を持つ cond 式 (define (interest-rate amount) (cond [(<= amount 1000) .040] amount ≦ 1000 のとき [(<= amount 5000) .045] 1000<amount≦5000のとき [(> amount 5000) .050] )) 5000 >amount のとき 次に3つの条件節内の結果値を考える (interest-rate 1500) から 0.045 が得られる過程 (interest-rate 1500) 最初の式 interest-rate の本体 = (cond (cond [(<= amount 1000) .040] [(<= 1500 1000) .040] [(<= amount 5000) .045] [(<= 1500 5000) .045] [(> amount 5000) .050]) [(> 1500 5000) .050]) にamount = 1500 の置き換え = (cond (<= 1500 1000) → false [false .040] [(<= 1500 5000) .045] [(> 1500 5000) .050]) [false 0.040] → 消える = (cond [(<= 1500 5000) .045] [(> 1500 5000) .050]) = (cond (<= 1500 5000) → true [true .045] コンピュータ内部での計算 [(> 1500 5000) .050]) = 0.045 実行結果 条件関数の開発:Test 定義完成後は事前に考えた関数例でテストすること! • Example として場合ごとに少なくともひとつ関数例を 考えた → 少なくとも以下の結果が true となるはず 例1. (= (interest-rate 1000) .040) 例2. (= (interest-rate 5000) .045) 例3. (= (interest-rate 8000) .050) 練習 月の日数 • 月 month を受け取り(数字)、その日数を 求める関数 easy-get-num-of-days を 作る。ただし閏年のことは考えない。 – まず月ごとに12通りに分けて考えてみよ。 – 日数は3通りしかない。3つのcond節を持つ cond 式 で考えよ。(比較演算と論理演算を組み合わせる) 記号情報 記号情報 Schemeの記号情報 (データは数値だけではない) –シンボル: ' が前置したキーボード文字の並び • 'the 'dog 'ate 'a 'chocolate 'cat! 'two^3 など • 注:( ) " , などは使えない、' がなければ変数(値を持つ)。 • 象徴的に何かを表す不可分なデータ –目的は名字や名前、職業的肩書、命令、通知などの記号的表現 –文字列: 2つの " で囲まれたキーボード文字の並び • "the dog" "isn't" "made of" "chocolate" "two^3"など • 文字のならび。シンボルと異なり分割できる複合データ –画像 • DrRacketは画像をサポート: –テキストの図7は惑星の写真を操作する関数の冒頭の例 種々のデータの属性判定、比較演算 • データの属性判定 number? boolean? symbol? string? など • 数値同士の比較 < <= = >= > など • シンボル同士の比較 symbol=? • 文字列同士の比較 string<? string<=? string=? string>=? など データの属性判定、比較演算の例 属性判定の例: 比較演算の例: (number? 5) = true (boolean? false) = true (symbol? 'hello) = true (symbol? "hello") = false では以下はどうだろう? (string? 'hello) (string? "hello") (< 3 4) = true (= 3 4) = false (symbol=? 'hello 'bye) = false (string=? "hello" "he") = false (string>? "hello" "bye") = true では以下は? (ヒント:辞書での順番) (string<? "he" "hello") (string<? "hello" "he") 練習問題:シンボルの条件関数 • 次の4種のシンボルに対応した「返答」を返すよ うな関数 reply を作る。 入力シンボル → 答え 'GoodMorning → 'Hi 'HowAreYou → 'Fine 'GoodAfternoon → 'NeedANap 'GoodEvening → 'BoyAmITired (これ以外の入力に対しては,実行エラー) C言語の場合,シンボル型がない const const const const int int int int GoodMorning=0; HowAreYou=1; GoodAfternoon=2; GoodEvening=3; などのように,最初に定義して,入力は,その定義した値にする か,文字列として扱う. #include <string.h> char grt[12]; scanf_s(“%12s”, grt,12);//VisualStudio scanf(“%s”, grt); // 標準C言語処理系 if (strcmp(grt, “GoodMroning”)==0) printf(“Hi\n”); これまでの Scheme Scheme も自然言語同様に語彙と文法を持つ 語彙 • 変数:関数と値の名前 • キーワード:句読点のようなもの – define, cond, else (変数には使用不可) • 定数 – 数: 5, -5, 0.5 など – ブール値: true, false – 記号的:シンボル、文字列 文法:語彙を用いてプログラム(式 と定義)を作る規則 定義 • 関数定義 – (define (関数名 変数並び) 式) • 変数定義 – (define 変数名 式) • プリミティブ演算:Scheme が最初 から提供している基本的な関数 式 – 四則演算子:+, -, *, / • 変数 – 比較演算子:<, <=, >, >=, = • 定数 – 奇数か偶数かの判定:odd?, even? – 論理演算子:and, or, not • プリミティブ演算の適用 – その他の演算子:remainder, • 定義した関数の適用 quotient, max, min, abs, sqrt, expt, log, sin, cos, tan, asin, acos, atanなど • 条件式 発展課題 課題1. うるう年の判定 • 西暦年 year から,うるう年であるかを求める関 数 is-leap? を作る • うるう年の判定法 – 4の倍数の年 ならうるう年、 – 但し, 100の倍数の年で400の倍数でない年は うるう 年ではない (4の倍数だが例外) • 2005年はうるう年でない(4の倍数でない) • 2004年はうるう年(4の倍数) • 2000年はうるう年(100の倍数で例外にも当てはまらない) • 1900年はうるう年でない(4の倍数で100の倍数だが400の 倍数でないので例外に相当) – 年がある数の倍数かを調べるため remainderを使う 課題2. 曜日を求める • 西暦の年,月,日から曜日を求める公式である、 ツエラーの公式のプログラム zellar を作る。 – ツエラーの公式では「1年の起点 を3月とし、月は3 月から14月まである」と考えている。(うるう年がある ので,1年の起点を3月とする方が計算が簡単) – 1月,2月は,前年の13,14月と考え、月は3から14 – 計算された曜日は「数字」で次の意味になる. 0 1 2 3 4 5 6 日曜 月曜 火曜 水曜 木曜 金曜 土曜 ツエラーの公式(数式表現) [(y+[y/4]+[y/400]-[y/100]+[(13m+8)/5]+d) mod 7] ここで y: 年、 d: 日、m: 3月を起点とする月で値 は3から14(1月,2月は前年の13,14月と考える) • この計算の結果値が0なら日曜,1なら月曜・・・ • 式中 [...] とあるのは,小数点以下切り捨て – 切捨て計算には,quotientを使う • modは剰余を計算。例えば 2003 mod 4 は 3 C言語では,y, m, dがint型の時, (y+(y/4)+(y/400)-(y/100)+(13*m+8)/5+d) % 7
© Copyright 2024 ExpyDoc