JavaScript/ビット演算
- JavaScript > ビット演算
ビット演算
編集JavaScriptはビット(二値)演算をサポートしています。
- & ビットごとのAND(論理積)
- | ビットごとのOR(論理和)
- ^ ビットごとの排他的 OR(排他的論理和)
- << 左シフト
- >> 右シフト
- >>> 符号なし右シフト演算子
- ~ 1の補数を得る
また、次の様な複合代入演算子も用意されている
- &= ビットごとのAND演算をして代入
- |= ビットごとのOR演算をして代入
- ^= ビットごとの排他的ORをして代入
- >>= 右シフトして代入
- <<= 左シフトして代入
- >>>= 符号なし右シフト演算子
JavaScriptでビット演算を行ううえで注意すべきことは、ビット演算を行う前にNumber型の値が32ビット整数に強制変換されるということです。
これは、JavaScriptの数値型は倍精度浮動小数点型(64ビットFloat)で、仮数部が53ビットであり、それ以下で最大の2の冪乗が32ビットという理由からです。
- コード例
// AND演算子(&) console.log(`AND演算子(&): 0b101 & 0b011 ------- 0b${(0b101 & 0b011).toString(2).padStart(3, '0')} `); // OR演算子(|) console.log(`OR演算子(|): 0b101 | 0b011 ------- 0b${(0b101 | 0b011).toString(2).padStart(3, '0')} `); // XOR演算子(^) console.log(`XOR演算子(^): 0b101 ^ 0b011 ------- 0b${(0b101 ^ 0b011).toString(2).padStart(3, '0')} `); // NOT演算子(~) console.log(`NOT演算子(~): ~0b101 ------- 0b${(~0b101 & 0b111).toString(2).padStart(3, '0')} `); // 左シフト演算子(<<) console.log(`左シフト演算子(<<): 0b101 << 1 ------- 0b${(0b101 << 1).toString(2).padStart(3, '0')} `); // 右シフト演算子(>>) console.log(`右シフト演算子(>>): 0b101 >> 1 ------- 0b${(0b101 >> 1).toString(2).padStart(3, '0')} `); // ゼロ埋め右シフト演算子(>>>) console.log(`ゼロ埋め右シフト演算子(>>>): 0b101 >>> 1 ------- 0b${(0b101 >>> 1).toString(2).padStart(3, '0')} `);
- 実行結果
AND演算子(&): 0b101 & 0b011 ------- 0b001 OR演算子(|): 0b101 | 0b011 ------- 0b111 XOR演算子(^): 0b101 ^ 0b011 ------- 0b110 NOT演算子(~): ~0b101 ------- 0b010 左シフト演算子(<<): 0b101 << 1 ------- 0b1010 右シフト演算子(>>): 0b101 >> 1 ------- 0b010 ゼロ埋め右シフト演算子(>>>): 0b101 >>> 1 ------- 0b010
2進法の表記法
編集JavaScriptでは、2進数を表す際には数値の前に 0b を付けます。例えば、0b1010 は10進数の10に対応します。
const binaryNumber = 0b1010; // 2進数の10を表す console.log(binaryNumber); // 出力: 10
補数
編集JavaScriptにおいて、負の整数は2の補数形式で表現されます。例えば、-5はビット反転(NOT演算子)を行い、1を加えた結果として表現されます。
const negativeNumber = -5; console.log(negativeNumber.toString(2)); // 出力: "-101"
ビットシフト
編集ビットシフト演算子は、ビット列を左または右に移動させます。左シフト演算子 << は数値を左にシフトし、右側にゼロを追加します。右シフト演算子 >> は数値を右にシフトしますが、符号ビットによって値を埋めます。
const number = 5; // 0b101 const leftShiftedNumber = number << 1; // 0b1010 (10) const rightShiftedNumber = number >> 1; // 0b10 (2) console.log(leftShiftedNumber, rightShiftedNumber);
論理演算
編集JavaScriptには論理演算子 AND (&)、OR (|)、XOR (^)、NOT (~) があります。これらの演算子は、対応するビットごとの論理演算を実行します。
const a = 0b1010; // 10 const b = 0b1100; // 12 console.log(a & b); // AND演算: 0b1000 (8) console.log(a | b); // OR演算: 0b1110 (14) console.log(a ^ b); // XOR演算: 0b0110 (6) console.log(~a); // NOT演算: 0b11111111111111111111111111110101 (-11)
これらの演算子は、ビットごとの操作を行うため、ビットマスクやビット操作を行う際に役立ちます。
イディオム
編集以下は、ビット演算のイディオムを1つのソースコードにまとめ、コメントで解説した例です。
/** * ビットフラグの操作 * @constant {number} FLAG_A - フラグAを表すビットパターン * @constant {number} FLAG_B - フラグBを表すビットパターン * @constant {number} FLAG_C - フラグCを表すビットパターン */ const FLAG_A = 1 << 0; // 0b0001 const FLAG_B = 1 << 1; // 0b0010 const FLAG_C = 1 << 2; // 0b0100 /** * ビットがセットされた数をカウントする関数 * @param {number} number - カウントする数 * @returns {number} セットされたビット数 */ function countSetBits(number) { let count = 0; while (number) { count += number & 1; number >>= 1; } return count; } /** * ビットマスクの使用 * @constant {number} MASK_CLEAR_BIT_3 - ビット3をクリアするマスク * @constant {number} MASK_SET_BIT_4 - ビット4をセットするマスク */ const MASK_CLEAR_BIT_3 = ~(1 << 2); // ビット3をクリアするマスク const MASK_SET_BIT_4 = 1 << 3; // ビット4をセットするマスク // ビットフラグの操作 let options = 0; options |= FLAG_A; // フラグAをセットする options |= FLAG_B; // フラグBをセットする console.log("オプション:", options.toString(2)); // オプション: 0b0011 // ビットがセットされた数をカウント console.log("ビットがセットされた数:", countSetBits(0b101010)); // ビットがセットされた数: 3 // ビットマスクの使用 let data = 0b1101; // 0b1101 data &= MASK_CLEAR_BIT_3; // ビット3をクリアする data |= MASK_SET_BIT_4; // ビット4をセットする console.log("ビットマスク適用後のデータ:", data.toString(2)); // ビットマスク適用後のデータ: 0b1111 // ビット反転 const number = 0b1010; // 0b1010 const flippedNumber = ~number; // ビットの反転 console.log("ビット反転:", flippedNumber.toString(2)); // ビット反転: -0b1011
このコードは、ビットフラグの操作、ビットカウント、ビットマスクの使用、そしてビット反転という4つのビット演算のイディオムを示しています。それぞれの手法は、ビット演算を行う際に非常に便利であり、効率的なコードを書くための重要なツールとなります。