Skip to content
uupaa edited this page Apr 21, 2016 · 38 revisions

Bit.js is a JavaScript library that supports the analysis of binary data. It aggregates the low-level bit manipulation functions.
(Bit.js はバイナリデータのパースなど、低レベルなビット操作関数を集約したライブラリです)

// get contiguous n bits (bit shift and mask).
// 連続したnビットを取り出します
Bit.n(0x000000ff, 0b00000000000000000000000011111100) // -> 0x3f,
Bit.n(0x000000ff, 0b00000000000000000000000011000000) // -> 0x03,

// bit split by bit-pattern
// Bit.splitN を使うとビットパターンを切り出せます
// 戻り値の先頭には第一引数の値がそのまま格納されています
Bit.split32(0xffff1234, [16,4,4,4,4])  // -> [0xffff, 0x1, 0x2, 0x3, 0x4]
                                       //         16    4    4    4    4    bit

Bit.split24(0xff1234, [16,4,4]) // -> [0xff, 0x1, 0x2, 0x3, 0x4]
Bit.split16(0x1234,   [8,8])    // -> [0x12, 0x34]
Bit.split8(0xfe,      [2,2,4])  // -> [0x3, 0x3, 0xe]

// With ES6 Destructuring Assignment
// ES6 Destructuring Assignment と Bit.splitN を併用すると以下のように簡便に記述できます
var [a, b, c] = Bit.split32(0x00001234, [16, 8, 8]);
// -> a = 0x12, b = 0x3, c = 0x4

// population count (counting 1 bits)
// 1のビットの数を数えます
Bit.popcnt(0x6) // -> 2

// count the number of contiguous 1 bits from Left-side or Right-side
// 連続した1のビットの数を左方向または右方向から数えます
Bit.cnl(0b11001110) // -> 2
Bit.cnr(0b11001110) // -> 3

// Number of Leading Zero
Bit.nlz(0x6)    // -> 29
Bit.clz(0x6)    // -> 29 (this function is an alias of Bit.nlz)

// Number of Training Zero
Bit.ntz(0x6)    // -> 1
Bit.ctz(0x6)    // -> 1 (this function is an alias of Bit.ntz)

// binary dump
// Bit.dump を使うとビットパターンをダンプできます
Bit.dump(0x12345678, [4,4,8,4,4,8]);
// -> "0001, 0010, 00110100, 0101, 0110, 01111000"

// verbose dump
// 第三引数(verbose) を true にすると情報量が増えます
Bit.dump(0x12345678, bitPattern, true);
// -> "00010010001101000101011001111000(0x12345678), 0001(1,0x1), 0010(2,0x2), 00110100(52,0x34), 0101(5,0x5), 0110(6,0x6), 01111000(120,0x78)"
//     0x12345678 の2進数表現                            (10進数,16進数)

// get IEEE754 expression
// Bit.IEEE754 を使うと数値の IEEE754 表現を取得できます
var doublePrecision = true;
var u32array = Bit.IEEE754(0.15625, doublePrecision);
Bit.dump(u32array[0], [1,11,20]) + Bit.dump(u32array[1], [32])
// -> "0, 01111111100, 0100000000000000000000000000000000000000000000000000"


// BitView
// BitView を使うとバイナリデータ、特にビットで圧縮されたヘッダ部分を簡単にパースできます
var bitView = new BitView(new Uint8Array([0, 1, 2, 3, 0xFF, 0xFE, 0xFD, 0xFC]));

                    // read 32 bit
bitView.u(32)       // -> 0x00010203

                    // read 24 bit
bitView.u(24)       // -> 0xFFFEFD

                    // read 1 bit
bitView.u(1)        // -> 0x1  `11111100` (0xFC)
                    //          ~

                    // read 2 bit
bitView.u(2)        // -> 0x3  `11111100` (0xFC)
                    //           ~~

                    // read 5 bit
bitView.u(5)        // -> 0x1C `11111100` (0xFC)
                    //             ~~~~~

開発フェーズと最適化について

開発初期段階においては Bit.splitN や Bit.dump を使い、ザクザクと記述していきます。
ある程度実装が落ち着いたら、ベンチマークを取得し、特に効果的がある部分は、 Bit.n や直接ビット演算で書き直すとよいでしょう。

// --- 開発中のコード(最適前の状態) ---
var u16 = 0xffee;

var bits = Bit.split16(u16, [1, 1, 1, 13]);
var a = bits[0]; // -> 1
var b = bits[1]; // -> 1
var c = bits[2]; // -> 1
var d = bits[3]; // -> 0x1fee

// --- Bit.n を使うことで可読性を維持しつつ程々に最適化したコード ---
var u16 = 0xffee;

var a = Bit.n(u16, 0b1000000000000000); // -> 1
var b = Bit.n(u16, 0b0100000000000000); // -> 1
var c = Bit.n(u16, 0b0010000000000000); // -> 1
var d = Bit.n(u16, 0b0001111111111111); // -> 0x1fee

// --- 実行速度最適化を施したコード(可読性は下がっています) ---
var u16 = 0xffee;

var a = u16 >>> 15 & 0x1;    // -> 1
var b = u16 >>> 14 & 0x1;    // -> 1
var c = u16 >>> 13 & 0x1;    // -> 1
var d = u16 >>>  0 & 0x1fff; // -> 0x1fee 

また、DevTools の watch式 やコンソールに Bit.dump の結果を表示しつつ実装をすすめると良いでしょう。

Bit.js と ES6

ES6 の Destructuring Assignment が使える環境では、さらに簡単に記述できるようになります。

var u16 = 0x0000ffee
var [a, b, c, d] = Bit.split16(u16, [1, 1, 1, 13]);
// a = 0x1, b = 0x1, c = 0x1, d = 0x1fee

Clone this wiki locally