代码笔记 - 从二进制流中以非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的场景下。

优势

类型肯定,能够避免数字转二进制字符串带来的性能开销。

相关文章
相关标签/搜索