为Javascript类型的数组创建位掩码

时间:2018-06-20 01:17:51

标签: javascript arrays compression

我正在与Javascript typed arrays合作,并且出于网络目的,我​​需要尽可能地对其进行压缩。

最小的内置数组Javascript每个条目为8位。这将存储0到255之间的数字。

但是我正在使用的数据只能包含0到3之间的数字。可以使用2位存储。

所以我的问题是,如果我有一个仅使用0到3之间的数字填充数据的8位数组,如何将其“转换”为2位数组? >

我知道我需要使用bit operator,但是我不确定如何制作一次仅聚焦于2位的掩码。

2 个答案:

答案 0 :(得分:1)

这是使用&>>将8位数字转换为长度为4的2位数组的功能:

function convert8to2(val){
    var arr = [];
    arr.push((val&parseInt('11000000', 2))>>6);
    arr.push((val&parseInt('00110000', 2))>>4);
    arr.push((val&parseInt('00001100', 2))>>2);
    arr.push((val&parseInt('00000011', 2)));
    return arr;
}
function convert2to8(arr){
    if(arr.length != 4)
      throw 'erorr';
    return (arr[0]<<6)+(arr[1]<<4)+(arr[2]<<2)+arr[3];
}
// 228 = 11100100
var arr = convert8to2(228);
console.log(arr);
console.log(convert2to8(arr));

已编辑

更改示例值并以0开头的二进制数字格式

已编辑

添加convert2to8并创建示例用法:

function convert8to2(val){
    var arr = [];
    arr.push((val&parseInt('11000000', 2))>>6);
    arr.push((val&parseInt('00110000', 2))>>4);
    arr.push((val&parseInt('00001100', 2))>>2);
    arr.push((val&parseInt('00000011', 2)));
    return arr;
}
function convert2to8(arr){
    if(arr.length != 4)
      throw 'erorr';
    return (arr[0]<<6)+(arr[1]<<4)+(arr[2]<<2)+arr[3];
}

var randomData = [];
for(var i=0;i<10;i++){
  randomData.push(Math.floor(Math.random() * 255));
}

console.log(randomData);

var arrayOf2 = []
for(var i=0;i<randomData.length;i++){
    arrayOf2.push(convert8to2(randomData[i]));
}
console.log(arrayOf2);

var arrayOf8 = [];
for(var i=0;i<arrayOf2.length;i++){
    arrayOf8.push(convert2to8(arrayOf2[i]));
}
console.log(arrayOf8);

答案 1 :(得分:1)

一个较长的例子很难放在评论中:)

请预先注意,网络数据经常已经被压缩-例如使用gzip(尤其是在担心数据量且网络库设置正确的情况下)。但是,情况并非总是如此,并且仍然不如手动完成那么紧凑。

您需要跟踪两件事,即当前数组索引和正在读取或写入的8位内部的当前插槽。对于写作,|对于阅读&是有用的。移位(<<>>)用于选择位置。

const randomTwoBitData = () => Math.floor(Math.random() * 4);

//Array of random 2-Bit data
const sampleData = Array(256).fill().map(e => randomTwoBitData());

//four entries per 8-Bit
let buffer = new Uint8Array(sampleData.length / 4);

//Writing data, i made my life easy
//because the data is divisible by four and fits perfectly.
for (let i = 0; i < sampleData.length; i += 4) {
  buffer[i / 4] =
    sampleData[i] |
    (sampleData[i + 1] << 2) |
    (sampleData[i + 2] << 4) |
    (sampleData[i + 3] << 6);
}

//padding for console logging
const pad = (s, n) => "0".repeat(Math.max(0, n - s.length)) + s;

//Some output to see results at the middle
console.log(`buffer: ${pad(buffer[31].toString(2), 8)}, ` +
`original data: ${pad(sampleData[127].toString(2), 2)}, ` +
`${pad(sampleData[126].toString(2), 2)}, ` +
`${pad(sampleData[125].toString(2), 2)}, ` +
`${pad(sampleData[124].toString(2), 2)}`);

console.log("(order of original data inverted for readability)");
console.log("");

//Reading back:
let readData = [];
buffer.forEach(byte => {
  readData.push(byte & 3);           // 3   is 00000011 binary
  readData.push((byte & 12) >> 2);   // 12  is 00001100 binary
  readData.push((byte & 48) >> 4);   // 48  is 00110000 binary
  readData.push((byte & 192) >> 6);  // 192 is 11000000 binary
});

//Check if data read from compacted buffer is the same
//as the original
console.log(`original data and re-read data are identical: ` +
readData.every((e, i) => e === sampleData[i]));