ビットシフト: 左シフトと右シフト演算
左シフトと右シフトのビット演算を理解。論理シフトと算術シフトの違い、2のべき乗による乗除算との等価性を解説します。
Binary (Base 2) → Binary (Shifted)Arithmetic
詳細な説明
ビットシフトは、2進数のすべてのビットを指定された位置数だけ左または右に移動します。CPU が実行できる最も高速な演算のひとつであり、効率的なアルゴリズムの基盤です。
左シフト (<<):
ビットを左に移動し、空いた位置をゼロで埋めます。左シフト1回ごとに値が 2 倍になります。
00001010 << 1 = 00010100 (10 x 2 = 20)
00001010 << 3 = 01010000 (10 x 8 = 80)
右シフト (>>):
ビットを右に移動します。右シフト1回ごとに 2 で割ります(整数除算、余りは切り捨て)。
00010100 >> 1 = 00001010 (20 / 2 = 10)
00010100 >> 2 = 00000101 (20 / 4 = 5)
論理シフト vs. 算術シフト:
- 論理シフト(JavaScript の
>>>): ゼロで埋めます。符号なし数に使用。 - 算術シフト(
>>): 符号ビットで埋めます(負の数を保持)。11110000 >> 2 = 11111100(先頭の 1 が保持される)。
パフォーマンスの優位性:
ほとんどの CPU では、シフトは乗除算よりもはるかに高速です。シフトによる 2 のべき乗の乗算は古典的な最適化手法です:
n * 4=n << 2n / 8=n >> 3n * 10=(n << 3) + (n << 1)
実用的な応用:
- カラーチャンネル抽出:
(pixel >> 8) & 0xFFで 24ビット RGB 値からグリーンチャンネルを抽出。 - 2のべき乗の計算:
1 << nで 2 の n 乗を計算。 - ビットフィールドのパッキング: シフトと OR で複数の小さな値をひとつの整数にまとめる。
- 高速平均:
(a + b) >> 1で2つの整数の平均を計算(オーバーフローに注意)。
よくある落とし穴:
- ビット幅を超えるシフトは C/C++ では未定義動作。
- C での負の数の
>>は実装依存(ただし、ほぼすべての最新コンパイラは算術シフトを使用)。 - JavaScript では、すべてのビット演算は数値が64ビット浮動小数点であっても32ビット整数として動作します。
ユースケース
ゲームエンジン開発者は、キャッシュ効率の良いエンティティシステムのために、複数のデータフィールド(位置、回転、フラグ)を32ビットまたは64ビットの単一の整数にパックおよびアンパックする際にビットシフトを使用します。