我正在与Javascript typed arrays合作,并且出于网络目的,我需要尽可能地对其进行压缩。
最小的内置数组Javascript每个条目为8位。这将存储0到255之间的数字。
但是我正在使用的数据只能包含0到3之间的数字。可以使用2位存储。
所以我的问题是,如果我有一个仅使用0到3之间的数字填充数据的8位数组,如何将其“转换”为2位数组? >
我知道我需要使用bit operator,但是我不确定如何制作一次仅聚焦于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]));