一只萌萌小番薯
之前说 JavaScript 最大支持 31 位的整数,抱歉,说错了,我用 Number.MAX_SAFE_INTEGER.toString(2).length计算了一下,结果是 53,也就是说 JavaScript 最大支持 53 位的整数。因此,我修改了答案。可以用 Uint32Array、Uint16Array 或者 Uint8Array 来封装 ArrayBuffer 来进行处理。按习惯用 Uint32Array 或 Uint8Array 合适一些。理论上 Uint32Array 会更快,但实际上要看 ArrayBuffer 的具体实现,这里不做速度上的比较。然后一般的位操作都直接算 index 就了,只有位移操作的时候需要计算上个位移移出的部分。Uint8Array 实现先写的这个答案,留在这了。后面用 Uint32Array 的实现可能更好一些。下面写了一个左移一位的操作,为了简化测试,只字义了4个字节(按字节而不是按整数处理的,所以可以模拟多个单元的情况)var buffer = new ArrayBuffer(4);var iBuffer = new Uint8Array(buffer);
iBuffer[0] = 0x03;
iBuffer[1] = 0xf0;console.log(Array.from(iBuffer).map(n => n.toString(2)));// [ '11', '11110000', '0', '0' ]let rest = 0;for
(let i = iBuffer.length - 1; i >= 0; i--) { const v = iBuffer[i]; const newRest = (v & 0x80) > 0 ? 1 : 0;
iBuffer[i] = ((v << 1) | rest) & 0xff;
rest = newRest;
}console.log(Array.from(iBuffer).map(n => n.toString(2)));// [ '111', '11100000', '0', '0' ]如果需要移多位,对 Uint8Array 来说,8位以内,都可以通过位移来算 newRest,比如,移3位的情况const newRest = v >> (8 - 3);但是对于移位大于 8 的情况就比较复杂一些了,需要计算 index 偏移(或者 8 位 8 位的移,再处理余下不足 8 位的情况)。所以总的来说我觉得这个算法还是比较考人的,不过我没搜到合适的 BitInteger 库,只找到一个 没提供位运算的,可以试试通过乘法(×2)和除法(÷2)来实现。又试验了一下,可以用 Uint32Array 来实现这样操作起来可能会更快一些var buffer = new ArrayBuffer(16);var iBuffer = new Uint32Array(buffer);
iBuffer[0] = 0x03;
iBuffer[1] = 0x8f000000;console.log(Array.from(iBuffer).map(n => n.toString(2)));// bits 需要小于32function shift(buffer, bits) {
let rest = 0; for (let i = iBuffer.length - 1; i >= 0; i--) { const v = iBuffer[i];
const newRest = v >>> (32 - bits);
iBuffer[i] = ((v << bits) | rest) & 0xffffffff;
rest = newRest;
}
}
shift(iBuffer, 5);console.log(Array.from(iBuffer).map(n => n.toString(2)));输出[ '11', '10001111000000000000000000000000', '0', '0' ]
[ '1110001', '11100000000000000000000000000000', '0', '0' ]