1 C言語入門 第4週 補足資料 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。) 2 閏年の判定を例に 条件判定の簡略化 3 閏年(leap year)の判定 • 3重のif-else文による実装 • 条件1を実装 真 偽 4で割れる if (year % 4 == 0) { leap_year_flag = 1; } else { leap_year_flag = 0; } 閏年 平年 4 閏年(leap year)の判定 • 3重のif-else文による実装 • 条件2を追加 真 偽 4で割れる if (year % 4 == 0) { if (year % 100 == 0) { leap_year_flag = 0; } else { leap_year_flag = 1; } } else { leap_year_flag = 0; } 真 偽 100で割れる 平年 閏年 平年 閏年判定の整理 • 3重のif-else文による実装 • 条件3を追加して完成 is_leap_year_1_1.c if (year % 4 == 0) { if (year % 100 == 0) { if (year % 400 == 0) { leap_year_flag = 1; } else { leap_year_flag = 0; } } else { leap_year_flag = 1; } } else { leap_year_flag = 0; } ごちゃごちゃしていて 分かり難い もっと分かり易く 書けないか? 真 真 偽 100で割れる 真 偽 400で割れる 閏年 偽 4で割れる 平年 閏年 平年 5 閏年判定の整理 • 3重のif-else文による実装 平年 • 平年フラグを外に追い出してみる leap_year_flag = 0; if (year % 4 == 0) { if (year % 100 == 0) { if (year % 400 == 0) { leap_year_flag = 1; } else { leap_year_flag = 0; } } else { leap_year_flag = 1; } } else { leap_year_flag = 0; } 真 偽 4で割れる 真 偽 100で割れる 真 偽 400で割れる 閏年 平年 閏年 平年 6 閏年判定の整理 • 3重のif-else文による実装 平年 • 平年フラグを外に追い出してみる leap_year_flag = 0; if (year % 4 == 0) { if (year % 100 == 0) { if (year % 400 == 0) { leap_year_flag = 1; } } else { leap_year_flag = 1; } } 少し短くなったが 対称性が崩れていて 少し美しくない 真 偽 4で割れる 真 偽 100で割れる 真 偽 400で割れる 閏年 平年 閏年 平年 7 閏年判定の整理 • 3重のif-else文による実装 閏年 • 逆に閏年フラグを外に追い出してみる leap_year_flag = 1; if (year % 4 == 0) { if (year % 100 == 0) { if (year % 400 == 0) { leap_year_flag = 1; } else { leap_year_flag = 0; } } else { leap_year_flag = 1; } } else { leap_year_flag = 0; } 真 偽 4で割れる 真 偽 100で割れる 真 偽 400で割れる 閏年 平年 閏年 平年 8 閏年判定の整理 • 3重のif-else文による実装 閏年 • 閏年フラグを外に追い出してみる leap_year_flag = 1; if (year % 4 == 0) { if (year % 100 == 0) { if (year % 400 == 0) { ; } else { leap_year_flag = 0; } } else { leap_year_flag = 0; } 真 偽 4で割れる 真の場合の処理が 空になっているのも 格好が良くない やはり 対称性が崩れていて 少し美しくない 真 偽 100で割れる 真 偽 400で割れる 閏年 平年 閏年 平年 9 閏年判定の整理 平年 真 • 3重のif-else文による実装 • 例外時に結果を随時上書きしてみる leap_year_flag = 0; if (year % 4 == 0) { leap_year_flag = 1; if (year % 100 == 0) { leap_year_flag = 0; if (year % 400 == 0) { leap_year_flag = 1; } else { leap_year_flag = 0; } } else { leap_year_flag = 1; } } else { leap_year_flag = 0; } 偽 4で割れる 閏年 真 偽 100で割れる 平年 真 平年 偽 400で割れる 閏年 閏年 平年 10 閏年判定の整理 平年 真 • 3重のif-else文による実装 • 例外時に結果を随時上書きしてみる leap_year_ex2_1.c 偽 4で割れる 閏年 真 leap_year_flag = 0; if (year % 4 == 0) { leap_year_flag = 1; if (year % 100 == 0) { leap_year_flag = 0; if (year % 400 == 0) { leap_year_flag = 1; } } } 短く対称性も取れていて 比較的美しい? 偽 100で割れる 平年 真 平年 偽 400で割れる 閏年 閏年 平年 11 12 西暦と閏年の集合 • 包含の関係 X • 西暦⊃X⊃Y⊃Z Y Z 閏年判定の整理 • 分解してみると 100 or 400で 割れる場合 400で 割れる場合 1 真 2 偽 真 4で割れる 平年 閏年 3 偽 真 100で割れる 平年 偽 400で割れる 閏年 1 2 3 100 or 400で 割れない場合 400で 割れない場合 13 14 閏年判定の整理 • 展開したif文による実装 • 100 と 400 は 4 の倍数 400 は 100 の倍数 である点に着目すると ネスト(入れ子)を展開可能 if文のロジック以外に 各条件間の数学的関係による 暗黙の前提が分からないと 読めないコードになるかも? そういう意味では 良くないコード? 適切なコメント等が必要? leap_year_ex2_1.c leap_year_flag = 0; if (year % 4 == 0) { leap_year_flag = 1; } if (year % 100 == 0) { leap_year_flag = 0; } if (year % 400 == 0) { leap_year_flag = 1; } year % 4 != 0 および year % 100 != 0 の場合には影響を与えない year % 4 != 0 の場合には影響を与えない 15 閏年判定の整理 • 展開したif文による実装 • 前頁のコードから省略可能な { } を省略 leap_year_ex2_2.c int leap_year_flag = if (year % 4 == 0) if (year % 100 == 0) if (year % 400 == 0) 0; leap_year_flag = 1; leap_year_flag = 0; leap_year_flag = 1; 実行する処理が 1つだけの場合は 省略出来る。 短くすっきりしていて見易い。 しかし、定義通りになっていないため、 100で割り切れた場合、4で割り切れなかった場合に影響を与えない 400で割り切れた場合、4,100で割り切れなかった場合に影響を与えない 事がわかっていないと混乱するかもしれない? 16 閏年判定の整理 • 3重の条件演算子による実装 • 条件1を実装 leap_year_flag = year % 4 == 0 ? 1 : 0; • 条件2を追加 leap_year_flag = year % 4 == 0 ? (year % 100 == 0 ? 0 : 1) : 0; • 条件3を追加して完成 leap_year_ex3_1.c leap_year_flag = year % 4 == 0 ? (year % 100 == 0 ? (year % 400 == 0 ? 1 : 0) : 1) : 0; 条件演算子は便利だけど 下手に多用すると読み難くなるので注意 ネスト(入れ子)が深くなると if-else文以上に読み難い 17 閏年判定の整理 • 3重の条件演算子による実装 • 条件1を実装 leap_year_flag = year % 4 == 0 ? 1 : 0; leap_year_ex2_2.c と同じ方法で 入れ子の条件を展開する例 • 条件2を追加 leap_year_flag = year % 4 == 0 ? 1 : 0; leap_year_flag = year % 100 == 0 ? 0 : leap_year_flag; • 条件3を追加して完成 leap_year_ex3_2.c leap_year_flag = year % 4 == 0 ? 1 : 0; leap_year_flag = year % 100 == 0 ? 0 : leap_year_flag; leap_year_flag = year % 400 == 0 ? 1 : leap_year_flag; これなら leap_year_ex2_2.c の方が読み易いかも? 18 論理演算 • AND, OR, NOT • 条件を論理演算する場合に使う • AND: • OR: • NOT: X && Y X || Y !X X Y X && Y X || Y FALSE FALSE 0 0 FALSE TRUE 0 1 TRUE FALSE 0 1 TRUE TRUE 1 1 !X 1 0 19 閏年判定の整理 • 西暦全体の集合のうち • X: 4で割り切れる集合(Y,Z を包含) • Y: 100で割り切れる集合(Z を包含) • Z: 400で割り切れる集合 X Y Z !Y Y 20 閏年判定の整理 • 論理演算で 考えると !X || (Y && !Z) X Y !X (X && !Y) || Z X && !Y C言語の演算子の優先度的には X && !Y || Z でも良いが ( ) を付けた方が理解が容易かつ 誤解の余地が生じない Y && !Z Z Z 21 閏年判定の整理 • if-else文と論理演算による実装 leap_year_ex4_1.c if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { leap_year_flag = 1; } else { leap_year_flag = 0; } • 論理演算による実装 leap_year_ex4_2.c leap_year_flag = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; 22 閏年判定の整理 • 全ての条件が網羅出来ているか? • 条件に漏れはないか? year % 100 == 0 year % 4 == 0 year % 100 != 0 year % 100 == 0 year % 4 != 0 year % 100 != 0 × の個所は 条件を満たす year が存在しない year % 400 == 0 閏年 year % 400 != 0 平年 year % 400 == 0 × year % 400 != 0 閏年 year % 400 == 0 × year % 400 != 0 × year % 400 == 0 × year % 400 != 0 平年 2_1, 2_2, 3_2 の例で year % 100 != 0 や year % 400 != 0 が 考慮不要なことが確認出来る。 23 閏年判定の整理 • 全ての条件が網羅出来ているか? 今の場合前の条件への追加条件なので • 条件に漏れはないか? 全ての組み合わせを考える必要はない year % 100 == 0 year % 4 == 0 year % 100 != 0 year % 100 == 0 year % 4 != 0 year % 100 != 0 year % 400 == 0 閏年 year % 400 != 0 平年 year % 400 == 0 year % 400 != 0 閏年 year % 400 == 0 year % 400 != 0 year % 400 == 0 year % 400 != 0 平年 24 閏年判定の整理 • 全ての条件が網羅出来ているか? • 条件に漏れはないか? year % 100 == 0 year % 100 != 0 × の個所は 条件を満たす year が存在しない year % 4 == 0 year % 4 != 0 year % 400 == 0 閏年 × year % 400 != 0 平年 × year % 400 == 0 × × year % 400 != 0 閏年 平年 長くなる場合は横に展開しても良い 25 閏年判定の整理 • 全ての条件が網羅出来ているか? • 条件に漏れはないか? × の個所は 条件を満たす year が存在しない year % 4 == 0 year % 100 == 0 year % 400 == 0 閏年 year % 4 == 0 year % 100 == 0 year % 400 != 0 平年 year % 4 == 0 year % 100 != 0 year % 400 == 0 × year % 4 == 0 year % 100 != 0 year % 400 != 0 閏年 year % 4 != 0 year % 100 == 0 year % 400 == 0 × year % 4 != 0 year % 100 == 0 year % 400 != 0 × year % 4 != 0 year % 100 != 0 year % 400 == 0 × year % 4 != 0 year % 100 != 0 year % 400 != 0 平年 この書き方は Excel 等で sort して調べるのに向いている 26 閏年判定の整理 • 真偽値による文字列の切り替え is_leap_year_template.c if (leap_year_flag) { printf("%d is leap year.\n", year); } else { printf("%d is not leap year.\n", year); } printf("%d is%s leap year.\n", year, leap_year_flag ? "" : " not"); leap_year_flag の値を見て直接 %s に埋め込む文字列を変更 27 同じ処理でも実装は様々 • 同じ処理でも複数の異なる実装が可能 • 効率や可読性等、何を重視するか? • 読み易い、理解しやすいコードを推奨
© Copyright 2025 ExpyDoc