代碼筆記 - 從二進制流中以非8bit讀取數據

/** *@global {Uint8Array} arr - 即字節流如[0xff,0xaa,0x10...] *@global {Number} pos - 二進制流索引,好比0的時候爲這個buffer的二進制第0位 * *@param {Number} size - 位數,範圍可爲1~31 *@return {Number} */
function read(size) {
    var i, code = 0;
    for (i = 0; i < size; i++) {
        if (arr[pos >> 3] & 1 << (pos & 7)) {
            code |= 1 << i;
        }
        pos++;
    }
    return code;
}
複製代碼

來源 github.com/intellilab/…javascript

說明

這個函數是用來讀取那些二進制流中,讀取規則並非8bit 16bit 64bit的數據格式。java

典型場景爲讀取gif數據流作解碼時,gif支持自定義位數編碼,好比對於黑白二值化的gif圖,能夠經過用2個bit編碼像素,相比8個bit編碼像素能夠大大減小文件體積。git

解析

1. 索引pos右移3位 pos>>3

能夠先看看pos>>3的幾個結果是什麼:github

0>>3 //0 
7>>3 //0
8>>3 //1
15>>3 //1
16>>3 //2
255>>3 //31
256>>3 //32
複製代碼

分析計算過程,對於任意二進制,能夠表示爲十進制計算爲:函數

n_0 \times 2^n + n_1 \times 2^{n-1} + ... +n_n \times 2^{0}

當往右移動三位,即丟棄末尾三位,而後總體除以2^3性能

n_0 \times 2^{n-3} + n_1 \times 2^{n-1-3} + ... +n_{n-3} \times 2^{3-3}編碼

2^3=8spa

因此右移以後的結果至關於把一個數除以8以後向下取整,即Math.floor(n/8);code

而一個字節恰好是8位二進制。 因此,pos>>3表明的是,在二進制流中,當前位數對應到字節碼裏面是第幾個字節。索引

2. 索引pos與7 pos & 7

一樣,先看看pos & 7的結果:

0 & 7 // 0
1 & 7 // 1
6 & 7 // 6
7 & 7 // 7
8 & 7 // 0
...
63 & 7 //7
64 & 7 //0
65 & 7 //1
複製代碼

能夠發現,計算的結果至關於對一個數求8的餘數,至關於n%8
分析計算過程,能夠把等式化爲二進制:

// 0 & 7 = 0
0b00000000 & 0b00000111 //-> 0b00000000

// 1 & 7 = 1
0b00000001 & 0b00000111 //-> 0b00000001

// 63 & 7 = 7
0b00111111 & 0b00000111 //-> 0b00000111

// 64 & 7 = 0
0b01000000 & 0b00000111 //-> 0b00000000

// 65 & 7 = 1
0b01000001 & 0b00000111 //-> 0b00000001
複製代碼

任意數字與7(n & 0b111),都是提取該數二進制模式的末三位;
所以不管所給的數字多大,末三位必定是按順序在0b0000b111之間,也就是0到7;
所以結果跟求8的餘數結果相同。
因此,pos & 7表示的是,當前位數對應到一個字節內第幾位

3. 判斷值arr[pos >> 3] & 1 << (pos & 7)

由上可知:
arr[pos >> 3]取到的是當前的字節,
pos & 7則是表明當前是字節內的第幾位。

由於1的二進制值爲0b00000001
根據位運算"與"的特性,任意數字與1(n & 0b00000001),能夠提取該數的末位的值;
發生左移時,
左移1位1<<10b00000010, 則能夠提取倒數1位的值
左移2位1<<20b00000100, 則能夠提取倒數2位的值
以此類推,
arr[pos >> 3] & 1 << (pos & 7)則能夠得到索引pos對應的二進制值0或1

4. code |= 1 << i

當索引pos取到的值爲1的時候,把值拼到code裏面。
for循環以後,就能夠拿到具體值。

限制

由於js位運算中左右移運算最大隻支持31位,所以參數size的最大隻能爲31。並且跨字節讀取數據還須要考慮大端序小端序的問題。所以最好是使用在小於8bit的場景下。

優勢

類型肯定,能夠避免數字轉二進制字符串帶來的性能開銷。

相關文章
相關標籤/搜索