ビット演算の計算ツール

ビットごとの論理演算とシフトの結果を、2進数の並びで確かめられます。マスクで特定のビットを取り出す、セットする、反転するといった操作や、シフトで2のべき乗の掛け算・割り算をする仕組みを、値を変えながら確かめてみてください。

値

16進数は 0x、2進数は 0b を先頭に付けます。負の10進数は2の補数として読みます。

結果

論理シフトは空いたビットを0で埋め、算術右シフトは最上位ビット(符号ビット)の値で埋めます。左シフトであふれたビットは捨てます。10進数の欄のかっこ内は、最上位ビットを符号とみなした2の補数の値です。

ビットごとの論理演算とマスク

AND・OR・XOR は、2つの値の同じ位置のビットどうしを演算します。AND は両方が1のときだけ1になるので、マスク(取り出したい位置だけ1にした値)と AND をとると、特定のビットだけを取り出せます。例の 0b10110100 AND 0x0F は下位4ビットの 0100 を取り出します。OR はビットを1にする(セットする)とき、XOR はビットを反転するときに使います。NOT は全ビットを反転します。

シフトと2のべき乗

左に k ビットシフトすると値は 2ᵏ 倍に、右に k ビットシフトすると 2ᵏ で割って切り捨てた値になります(はみ出さない範囲で)。掛け算や割り算より速いので、コンパイラは 2 のべき乗の掛け算・割り算をシフトに置き換えます。負の数を右にシフトするときは、符号ビットで埋める算術シフトを使うと、2の補数の値を 2ᵏ で割った結果(負の方向への切り捨て)になります。空いたビットを0で埋める論理シフトでは、負の数は大きな正の数になってしまいます。

ローテート(回転)

ローテートは、はみ出したビットを反対側に戻すシフトです。ビットが失われないので、暗号やハッシュ関数の計算、CRC の計算などで使われます。多くの CPU にはローテートの命令がありますが、C 言語にはローテートの演算子がないので、(x << k) | (x >> (w − k)) のように2つのシフトと OR で書き、コンパイラがローテートの命令に置き換えます。

よく使うビット演算の技

x AND 1 で奇数か偶数かが分かり、x AND (x − 1) で最も下の1のビットを消せます(これを繰り返すと1のビットの数を数えられます)。x AND (x − 1) が0なら、x は2のべき乗です。フラグ(状態を表すビット)の集まりを1つの整数で表し、OR でセット、AND と NOT でクリア、XOR で反転、AND で確認する使い方は、組込みのプログラムでレジスタを操作するときによく使われます。

関連する問題を解く

x と y は8ビットの符号なし整数とする。<< と >> は論理シフトで、空いたビットには0が入り、8ビットからあふれたビットは捨てる。∨ はビットごとの論理和を表す。次のプログラムを実行した後の y の値はどれか。

  1. A27
  2. B54
  3. C58
答えと解説を見る

正解:B. 54

13 は2進数で 00001101 です。x << 2 は2ビット左へずらして 00110100 = 52、x >> 1 は1ビット右へずらして 00000110 = 6 です(はみ出した最下位の1は捨てられます)。論理和は 00110110 = 54 です。52 と 6 は4の位のビットがどちらも1なので、足し算の 52 + 6 = 58 とは一致しません。

x と y は8ビットの符号なし整数とする。<< と >> は論理シフトで、空いたビットには0が入り、8ビットからあふれたビットは捨てる。∨ はビットごとの論理和を表す。x が 75 のとき、次の代入を実行した後の y の値はどれか。

  1. A75
  2. B180
  3. C210
答えと解説を見る

正解:B. 180

75 は2進数で 0100 1011 です。x << 4 は下位4ビットを上位へ移して 1011 0000 = 176(あふれた 0100 は捨てられます)、x >> 4 は上位4ビットを下位へ移して 0000 0100 = 4 です。論理和は 1011 0100 = 180 で、上位4ビットと下位4ビットを入れ替えた値になります。8ビットに収めずに 75 × 16 = 1200 のまま扱うと、結果が変わります。

整数 x を10倍する計算を、掛け算の命令を使わずにシフトと足し算で行う式として正しいものはどれか。

  1. A(x << 3) + (x << 1)
  2. B(x << 10)
  3. C(x << 2) + x
答えと解説を見る

正解:A. (x << 3) + (x << 1)

左に1ビットずらすと2倍になるので、x << 3 は8倍、x << 1 は2倍です。8x + 2x = 10x となるので、(x << 3) + (x << 1) で10倍が計算できます。定数を掛ける掛け算は、このようにシフトと足し算の組み合わせに置き換えられ、コンパイラも速い方を選んで使います。x << 10 は 2¹⁰ = 1024倍、(x << 2) + x は 4x + x = 5倍になります。シフトのビット数を10倍と取り違えないよう注意が必要です。

8ビットの符号付き整数で −8(1111 1000)を算術右シフトで1ビット右にずらした結果はどれか。

  1. A124(0111 1100)
  2. B−16(1111 0000)
  3. C−4(1111 1100)
答えと解説を見る

正解:C. −4(1111 1100)

算術シフト(算術右シフト)では、空いた最上位のビットに符号ビットをコピーするので、1111 1000 は 1111 1100 になり、これは2の補数で −4 です。負の数でも、右に1ビットずらすと2で割った値になります。最上位に0を入れる論理右シフトでは 0111 1100 = 124 となり、符号が変わってしまいます。−16は左に1ビットずらした結果です。C言語で負の符号付き整数を右シフトしたときにどちらになるかは、処理系定義(処理系に任されている)である点にも注意が必要です。

C言語で、int型の −7 / 2 と −7 >> 1(算術右シフトの場合)の結果の組み合わせとして正しいものはどれか。

  1. A−7 / 2 は −3、−7 >> 1 は −4
  2. Bどちらも −4
  3. C−7 / 2 は −4、−7 >> 1 は −3
答えと解説を見る

正解:A. −7 / 2 は −3、−7 >> 1 は −4

C言語(C99以降)の整数の割り算は、結果を0の方向に切り捨てると定められているので、−3.5 は −3 になります。一方、算術右シフトは小さい方(負の無限大の方向)に切り捨てる働きになり、−7(1111 1001)を右に1ビットずらすと 1111 1100 = −4 になります。そのため、負の数ではシフトと割り算は一致しません。コンパイラが2での割り算をシフトに置き換えるときは、負の数のための補正の命令を加えています。正の数なら両者は一致します。

よくある質問

算術シフトと論理シフトの違いは何ですか?

左シフトはどちらも同じで、空いた下位のビットを0で埋めます。右シフトでは、論理シフトは上位を0で埋め、算術シフトは符号ビットの値で埋めます。符号付きの数を2のべき乗で割るときは算術シフトを使います。

マスクとは何ですか?

取り出したり変えたりしたいビットの位置を1(または0)にした値です。AND でビットの取り出しやクリア、OR でセット、XOR で反転に使います。

10進数の欄のかっこの中の負の数は何ですか?

最上位ビットを符号とみなして、2の補数として読んだときの値です。たとえば8ビットの 0b10110100 は、符号なしなら180、符号付きなら −76 です。

試験ではどのように問われますか?

基本情報技術者試験などでは、マスクとの AND・OR・XOR の結果を求める問題、シフトによる掛け算・割り算、算術シフトと論理シフトの違い、科目Bではビット演算を使うプログラムのトレースが出題されます。

関連する用語

ビット演算 2の補数

関連する計算ツール

半導体・電子回路・情報の計算ツール →