情報処理Ⅱ 第4回 2007年10月29日(月) 本日学ぶこと 演算子(Operator) +, -, =, %, ++ ,&& ,||, == など C言語ではどんな演算子が使用できるか? 演算子間の優先順位はどうなっているか? • 例: 1 + 2 * 3 と書けば,(1 + 2) * 3 ではなく 1 + (2 * 3) と解釈される.このとき,* は + よりも 優先順位が高いという. 問題 整数が与えられたとき,そのビットパターンを出力できる? • 例: (char型の) 40 のビットパターンは,00101000 • int型やlong型,float型のビットパターンは? 2 演算子一覧 1. 関数呼び出し( ),配列の添字[ ],構造体のメンバ参照(., ->) 2. 単項演算子(!, 単項*, ++, 単項+, sizeof, キャストなど) 3. 乗除(2項*, /, %) 4. 加減算(2項+, 2項-) 5. シフト(<<, >>) 6. 関係(<, >, <=, >=) 7. 関係(==, !=) 8. ビット演算(&) 9. ビット演算(^) 10. ビット演算(|) 11. 論理演算(&&) 12. 論理演算(||) 13. 3項演算子(? :) 14. 代入演算子(=, +=など) 15. コンマ(,) 入p.314 リpp.155-156 高い 優 先 順 位 低い 優先順位を変えたければ,( ) で囲む.( ) が何重にもなること がある.{ } や [ ] は,この目的で使用できない. 3 単項演算子 増分演算子,減分演算子: ++, -正負の符号: +, sizeof演算子: sizeof キャスト演算子: (型名) リp.158 sizeof(char) は 1 char x; に対して sizeof(x) も 1 実数型やポインタ型の変 数もオペランドにできる. オペランドは変数名,式 もしくは型名. 慣習として ( ) をつけるが, 関数呼び出しではない. ( ) は必須 1/3 は 0 (float)1/3 は 0.333… (float)(1/3) は 0.0 4 単項演算子:注意点 原則として,オペランドの前(左)につける. 増分演算子と減分演算子はオペランドの後ろにつけることも できるが,前につけるのと意味が異なる. x = --y; ⇒ 「y = y - 1; x = y;」 と同じ(減分を先 に評価). x = y--; ⇒ 「x = y; y = y - 1;」 と同じ(減分を後 で評価).(x = y)--; ではない. 増分演算子と減分演算子のオペランドは,左辺値であり,か つ算術型またはポインタ型でなければならない. 入pp.209-210 リp.158 5 ビット演算子 整数値をビット(0と1)の並びとみなし,ビット単位 (bitwise)で演算を行う. ビット単位AND: & (2項演算子) ビット単位OR: | (2項演算子) ビット単位XOR: ^ (2項演算子) ビット単位NOT: ~ (単項演算子) 例: 1 & 2 は0である. 優先順位は ~ > & > ^ > | 代入演算子 &=, |=, ^= も利用可能. 入p.203-204 リp.161 6 ビット演算 x y x&y x|y x^y x ~x 1 1 1 1 0 1 0 0 1 0 1 1 0 1 1 0 0 1 1 0 0 0 0 0 ビット単位の演算結果であることに注意. 0 ^ 1 = 1 ^ 0 = 1 (相補律) 1 ^ 1 = 0 (ビットの反転), x ^ x = 0 (ビットのクリア)が成り立つ. 7 ビット演算子の利用例 一部のビットを0にする. 一部のビットを1にする. 入p.205 x & 0x0f : 00000011 x | 0x0f : 00101111 x ^ 0x0f : 00101100 char x = 0x23; のとき x ^ 0x0f は 0x2c,x ^ 0xf0 は0xd3. 全部のビットを反転する. 0x0f : 00001111 char x = 0x23; のとき x | 0x0f は 0x2f,x | 0xf0 は0xf3. 一部のビットを反転する. char x = 35; のとき x & 0x0f は 3,x & 0xf0 は32. x=35 : 00100011 ~x : 11011100 x = ~x; とすればよい. 8 シフト演算子 整数値をビットの並びとみなす. いずれも2項演算子で,左オペランドは整数値,右オペランド はシフトするビット数(0以上の整数値). 左シフト: << 右シフト: >> 5 << 3 は 40 m << n は m×2n m >> n は m×2-n 5 → 00000101 ← 40 >> 3 5 << 3 → 00101000 ← 40 負の数を右シフトしたときの結果は処理系依存. 代入演算子 <<=, >>= も利用可能. 入pp.205-206, p.123 リp.159 9 ビットパターン出力プログラム:準備 対象(入力)は,unsigned char型の値 簡単のため ビット長が分かれば,他の整数型にも適用可能 x=40 … char40.c 0 0 1 0 1 0 0 0 10 ビットパターン出力プログラム 検査方法 bの初期値は,1 << 7 bの「増分」は,b >>= 1 xの値は変化しない x: 0 0 1 0 1 0 0 0 b: 1 0 0 0 0 0 0 0 x & bは0 ⇒ 0 を出力 b: 0 1 0 0 0 0 0 0 x & bは0 ⇒ 0 を出力 b: 0 0 1 0 0 0 0 0 x & bは非0 ⇒ 1 を出力 0 0 1 x & bは0 ⇒ 0 を出力 … b: 0 0 0 0 0 11 3項演算子 オペランド1 ? オペランド2 : オペランド3 例: t = (a > b) ? a : b; ⇒ if (a > b) {t = a;} else {t = b;} と同じ 演算結果は左辺値ではない まずオペランド1を評価する.それが真であればオペランド2を, 偽であればオペランド3を評価して,その値を演算結果とする. × a > b ? a : b = 10; ○ *(a > b ? a : b) = 10; a, bはポインタ変数 3項演算子の入れ子も可能だが,読みにくい 入p.216 リpp.162-163 12 その他の演算子 関数呼び出し: ( ) 配列の添字: [ ] コンマ演算子: , for (i=0, max=-1; scanf("%d", &d[i]) == 1; i++) これらは構文の一部であり,演算子ではない. リp.157, p.165 13 補足 Cらしい式の例 結合規則 代入の順序 14 Cらしい式の例 xの値を1だけ増やす xの値を倍にする 実数なら,x *= 2; 正の整数なら, x <<= 1; xが偶数か奇数か判定する x++; if (x & 1) 初回授業で紹介した「if (x % 2)」は,やや非効率 xが0か否か判定する if (!x) ただし,if (x == 0) を推奨する 15 結合規則 同じ優先順位の演算子が並ぶ場合にも,評価の順序があり, 「結合規則」または「結合の向き」と呼ばれる. 左から右への結合(左結合) x = y - z + 2; ⇒ x = (y - z) + 2; と同じ 右結合でない演算子 右から左への結合(右結合) x += y = z + 2; ⇒ x += (y = z + 2); と同じ 単項演算子,3項演算子,代入演算子 入p.314 リp.148 16 代入の順序 オペランドの評価順序は,特に明記したものを除いて,不定 (処理系依存)である.式の中で同一の変数などに2つ以上 の代入をしないよう心がける. リp.177 例: x=2; printf("%d %d", ++x, ++x); の出力は 「3 4」かもしれないし,「4 3」かもしれない. 例: x % 2 ? (x = x * 3 + 1) : (x /= 2); は意 図通りに動作する(が,if文で書くほうが自然). 「副作用完了点」という概念もあるが,授業では説明しない. 17 まとめ Cでは多彩な演算子が利用できる.いくつかは数学の記号に 近く,いくつかはC独特である. 演算子ごとに「優先順位」と「結合規則」が決まっている. 真偽の扱い,評価されない式にも注意する. 18 値の評価の注意点 オーバーフロー アンダーフロー 計算誤差 暗黙の型変換 19 範囲を越えるとどうなるか? signed char型変数に13*13を格納すると? 13はint型定数で,13*13は,int型の169と評価される. これをsigned char型変数に格納しようとすると,169から 256を引いた-87が代入される. signed char a = 127; a++; だと,aの値は128では なく-128になる. 値が,型の取り得る範囲を超えるために,変わってしまうこと を,オーバーフロー(桁あふれ)という. 入p.134 リp.151 13x13.c 20 無限小? 1から始めて2でどんどん割っていくと,いずれは0になる. double d; for (d = 1; d > 0; d /= 2) { printf("%g\n", d); } 浮動小数点数の計算で,表現できる精度よりも小さくなり,値 が変わる(0などになる)ことを,アンダーフローという. 21 1なのに,1でない? for文を用いて,0, 0.1, 0.2, ..., 1.0 を取り出す, 間違った方法 double d; for (d = 0; d != 1; d += 0.1) 0.1という値を,計算機内で誤差なく表現できない.「計算誤 差」により,0.1×10が1でないという事態が起こる. プログラミングの心がけ (最善) 実数型はループ用変数にしない. (次善) != ではなく,> や < を用いて判定をする. 入pp.136-137 リp.66 from0to1bad.c 22 異なる型の値同士の計算 1/3 と 1.0/3 と 1/3.0 と 1.0/3.0 は同じ値? 算術演算において,大きい範囲の型に揃えられる. int > short, int > char (汎整数拡張) long double > double > float > long long > long > int (暗黙の型変換) unsigned > signed プログラミングの心がけ unsignedとsignedの整数値を混在させて演算しない. 1/3 は,0.それ以外の上の式はすべて0.333… リpp.150-153 23 代入時の型変換 代入演算子では,必ず左辺の型に変換される. double d; int x; に対して x = d = 1.0/3.0; ⇒ d = 0.333…; x = 0; と同じ d = x = 1.0/3.0; ⇒ x = 0; d = 0.0; と同じ 24 まとめ オーバーフロー,計算誤差,型変換に注意. 25
© Copyright 2024 ExpyDoc