========================================
東工大杯の準備は着々と進んでおらず、テスト対策もしていない中の人です。
=========================================
話は変わりまして、ビット演算の話。
そもそもこんな記事を書いたのは趣味で少しかじったからであって、別段他人に見せるほどでもないんですが、とりあえず書いときます。
ビット演算とは何かという話は他の人に譲るとして、実際の演算子を紹介していきます。
1.NOT
Cでの記号(演算子): ~ (チルダ)
論理演算のNOTに相当。数字をビット毎に反転させる。
例:
a : 0101 0101
b ~= a : 1010 1010
2.AND
Cでの記号(演算子): &
論理演算のANDに相当。2つの数字のビット毎にANDをとる。
例:
a : 0101 0101
b : 1111 0000
a & b : 0101 0000
3.OR
Cでの記号(演算子): | (バーティカルバー)
論理演算のORに相当。2つの数字のビット毎にORをとる。
例:
a : 0101 0101
b : 1111 0000
a | b : 0101 0000
4.XOR
Cでの記号(演算子): ^ (キャレット)
論理演算のXORに相当。2つの数字のビット毎にXORをとる。
例:
a : 0101 0101
b : 1111 0000
a | b : 0101 0000
ちなみにXORは以下の通り
X Y | Z
----+--
0 0 | 0
1 0 | 1
0 1 | 1
1 1 | 0
さてここからビット演算特有のビットシフトの話。ビットシフト自体はそこまで難しくはない(ずらすだけ)が、ビットシフトの種類で空いたところに何が入るかが変わるの(特に右シフト)で注意。
5.論理左シフト
Cでの記号(演算子): << ("Double less-than sign" とか言うらしい)
n-bit分左にずらし、空いたbitには"0"を入れる。
例:
a : 0101 0101
a << 3 : 1010 1000
6.算術左シフト
記号も動作も5.論理左シフトと同じなので割愛
ここからがわけわからん右シフトの世界
7.論理右シフト
Cでの記号(演算子): >> ("Double greater-than sign" とか言うらしい)
n-bit分右にずらし、空いたbitには"0"を入れる。
例:
a : 0101 0101
a >> 3 : 0001 0101
Cでの記号(演算子): >>
n-bit分右にずらし、空いたbitには..."1"か"0"を入れる
例①:
a : 0101 0101
a >> 3 : 0001 0101
例②:
b : 1010 0101
b >> 3 : 1111 0100
"算術右シフトでは、操作する前の一番上のbitを空いたところに入れる"
というルールがあるためです。(理由はGoogle先生に聞いてみよう!!!!!!!)
ここまでで、Cで使えるすべてのビット演算が出てきました。
全部の演算子が出てきたんだし、C言語だったらビット演算できる...なんて思ってませんよね?
ここである記号についてみてみましょう
5.論理左シフト
Cでの記号(演算子): <<
6.算術左シフト
Cでの記号(演算子): <<
5.論理右シフト
Cでの記号(演算子): >>
5.算術右シフト
Cでの記号(演算子): >>
あれ、記号が同じだ...。
そうです、C言語ではシフトの記号が論理と算術とで分けられていません!!!!!!!!!!!!!!!!!!
何たる失態。
ところでC言語の規格書(日本語で書かれたものだとJIS X 3010:2003)というものが世の中には存在しまして、こいつの中にはビットシフトについてこう書いてあります。
E1<<E2の結果は,E1 を E2 ビット分左にシフトした値とする。空いたビットには 0 を詰める。
E1 が符号無し整数型をもつ場合,結果の値は,E1×2^E2の,結果の型で表現可能な最大値より 1 大きい値を法とする剰余とする。
E1 が符号付き整数型と非負の値をもち,E1×2^E2が結果の型で表現可能である場合,それが結果の値となる。
それ以外の場合,その動作は未定義とする。
E1>>E2の結果は,E1 を E2 ビット分右にシフトした値とする。
E1 が符号無し整数型をもつ場合,又はE1が符号付き整数型と非負の値をもつ場合,結果の値は,E1/2^E2の商の整数部分とする。
E1 が符号付き整数型と負の値をもつ場合,結果の値は処理系定義とする
つまり左シフトは算術でも論理でも空いたビットには"0"が入るが、
右シフトは動作している環境で違うってこのらしい。
(´・ω・`)
環境依存である以上算術シフトと論理シフトについて議論してもあまり意味がないのですが、例えばGCCだとビットシフトする方の型をunsignedにしておくと論理シフトで、signedにしておくと算術シフトになったりします。
こんな感じで最後にトラップがありましたが、とりあえずビット演算の初歩の初歩の初歩はクリアできそうですね!
©2017 shts All Right Reserved.