こういう風なことを実現したいです。
- 数値(2進数表記)の 10110111 がある
- そのn~mビット目を抽出したい
- 例えば3~5ビット目なら 110 みたいに
※ ただし n , m は1から始まる番号
もちろんビット演算を使えば可能です。
ただ少し混乱することが多いので、
自分用にビット抽出方法とコード例をまとめました。
このページの目次
まずビット演算子(左シフト/右シフト)について
まず大前提として次の2つ演算子を利用します
- << : ビットの左シフト
- >> : ビットの右シフト
簡単にまとめると次の通りです。
ビットの左シフト(<<) の動作と使い方
これはビットを左にnビット詰める演算子
▼ ある数値を4ビット左シフトする例
1 2 3 4 5 6 7 |
let num = 255 console.log(num.toString(2)) /// => 11111111 num = num << 4 console.log(num.toString(2)) /// => 111111110000 |
左にシフトした分は 0 で埋められます。
ちなみに2進数を扱うときは num.toString(2) とすると2進数表記で数値(というか文字列)を確認できます。このテクニックはビット演算の動作を確認するのに便利です。
そして上コードの左シフトですが……
細かく丁寧に分解すると次の動作をしてます。
▼ 左シフトの動作イメージ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/// 元の2進数 000011111111 /// 左に1ビットシフト 000111111110 ^ /// 左に1ビットシフト 001111111100 ^^ /// 左に1ビットシフト 011111111000 ^^^ /// 4ビット左シフト完了! 111111110000 ^^^^ |
とにかく左に詰めてるイメージ
ビットの右シフト(>>) の動作と使い方
これはもう単純に左シフトの逆です。
▼ ある数値を4ビット右シフトする例
1 2 3 4 5 6 7 |
let num = 255 console.log(num.toString(2)) /// => 11111111 num = num >> 4 console.log(num.toString(2)) /// => 1111 |
右にシフトした分は 0 で埋められます。
これも一応動きを確認してみましょう
▼ 右シフトの動作イメージ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/// 元の2進数 11111111 /// 右に1ビットシフト 01111111 ^ /// 右に1ビットシフト 00111111 ^^ /// 右に1ビットシフト 00011111 ^^^ /// 4ビット右シフト完了! 00001111 ^^^^ |
演算子の向き( >> )で覚えればOK
n~mビット目までを抽出する方法とコード例
ようやく本題に入ります。
ある2進数の数値・データに対して、
「n~mビット目までを数値として抽出」
こういう操作をするための方法についてです。
▼ 単純に次のコードでビット抽出可能
1 2 3 4 |
let num = 255 /// n~mビット目までを抽出 (((1<<(m-n+1))-1) & (num>>(n-1))) |
▼ 汎用性を考えて関数化
1 2 3 |
function extractBits(num, n, m){ return (((1<<(m-n+1))-1) & (num>>(n-1))) } |
この関数は前半と後半に分けられます。
- 前半 :
((1<<(m-n+1))-1)
この部分ではマスク用のビット列を作成。例えば n = 2, m = 6 なら抽出ビット数は 5 になるため、 ((1<<(6-2+1))-1) = ((1<<5)-1) = (b100000-b1) = b11111 のビット列ができあがる。
- 後半 :
(num>>(n-1))
この部分ではnビットだけ右シフトしている。これと前述のマスク用ビット列のビット積を取ることでn~mビットだけの値が取得できる。
そしてもう1つ重要なことがあります。
それは右端から左にn~mビットを抽出すること
左端から右ではないので注意してください
このextraBits()によるビット抽出の例
いくつか適当なビット列で試してみます。
▼ n~mビット目までのビット抽出のコード例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
let num = 97 console.log(num.toString(2)) /// => 01100001 extractBits(num,3,6).toString(2) /// 結果 : 1000 /// /// 解説 : 01100001 /// ^^^^ let num = 233 console.log(num.toString(2)) /// => 11101001 extractBits(num, 5, 8).toString(2) /// 結果 : 1110 /// /// 解説 : 11101001 /// ^^^^ let num = 3571 console.log(num.toString(2)) /// => 110111110011 extractBits(num, 7, 11).toString(2) /// 結果 : 10111 /// /// 解説 : 110111110011 /// ^^^^^ |
※ 分かりやすさ優先のためにMonospacefフォント使用
任意範囲のビット抽出が可能。こういう感じです。
ビット抽出はマニアックだけど使われる場面が多い
マニアックというと少し語弊があるけど…
- バイナリフォーマットの解析をしたい時
- 数値をバイナリとして扱いたい時
- データを無駄なく神経質に扱いたい時
こういう場面で役立つかもしれません。
以上、JSでのn~mビット抽出でした。ではまた