首页 > 解决方案 > 使用逻辑运算符将 Int 编码为字节

问题描述

我最近一直在做一些关于逻辑算术的工作。我想将无符号整数(Uint's)和有符号整数(Int's)编码为字节。

下面是当前将 UInts 转换为字节的代码片段,反之亦然。不幸的是,我在用我的策略编码有符号整数时遇到了一些问题。

将使用这种移位和掩码方法对无符号和有符号整数执行整数编码。

for (let i=0; i<n; i++)
    buffer.push((value >>> (i*8)) & 0xFF);

那么我的readInt-method 有什么问题以及如何解决这个问题?

const buffer = [];

const writeIntN = (value, n) => {
  for (let i=0; i<n; i++)
    buffer.push((value >>> (i*8)) & 0xFF);
}
const readUint = (n, offset) => {
  let v=0;
  for (let i=0; i<n; i++)
    v |= (buffer[offset++] << (i*8));
  return v >>> 0;
}
const readInt = (n, offset) => {
  return readUint(n, offset) << (8*n) >> (8*n); // error is here
}


const writeUInt16 = (value) => writeIntN(value, 2);
const readUInt16 = (offset) => readUint(2, offset);


const writeInt16 = (value) => writeIntN(value, 2);
const readInt16 = (offset) => readInt(2, offset);

const writeInt8 = (value) => writeIntN(value, 1);
const readInt8 = (offset) => readInt(1, offset);



writeUInt16(20);
writeInt16(-20);
writeInt8(-42);
console.log(buffer);
console.log(readUInt16(0));
console.log(readInt16(2));
console.log(readInt8(4)); // how?


注意:我知道解码 8,16 位有符号整数的基本操作,但如何readUint更有效地在 for 循环中获取它?

解码 8 位有符号整数:(buffer[offset++] << 24) >> 24

解码 16 位有符号整数:(((buffer[offset++] << 0) | (buffer[offset++] << 8)) << 16) >> 16

标签: javascriptlogicbyteinteger-arithmetic

解决方案


那么我的 readInt 方法有什么问题以及如何解决这个问题?

修复:更改(8*n)(8*(4-n)).

const readInt = (n, offset) => {
  return readUint(n, offset) << (8*(4-n)) >> (8*(4-n));
}

或者,等效地,

const readInt = (n, offset) => {
    let v =0;
    for (let i=4-n; i<4; i++)
        v |= (buffer[offset++] << (i*8));
    return v >> (8*(4-n));
}

JavaScript 位运算符使用 32 位(4 字节)整数。左移 ( <<) 运算符丢弃左移的位。右移运算符 ( >>) 传播最左边(符号)位。

console.log();
writeUInt16(20);
writeInt16(-20);
writeInt8(-42);
console.log(buffer);
console.log(readUInt16(0));
console.log(readInt16(2));
console.log(readInt8(4));

[ 20, 0, 236, 255, 214 ]
20
-20
-42

const buffer = [];

const writeIntN = (value, n) => {
  for (let i=0; i<n; i++)
    buffer.push((value >>> (i*8)) & 0xFF);
}
const readUint = (n, offset) => {
  let v=0;
  for (let i=0; i<n; i++)
    v |= (buffer[offset++] << (i*8));
  return v >>> 0;
}

const readInt = (n, offset) => {
  return readUint(n, offset) << (8*(4-n)) >> (8*(4-n));
}

const writeUInt32 = (value) => writeIntN(value, 4);
const readUInt32 = (offset) => readUint(4, offset);

const writeInt32 = (value) => writeIntN(value, 4);
const readInt32 = (offset) => readInt(4, offset);

const writeUInt16 = (value) => writeIntN(value, 2);
const readUInt16 = (offset) => readUint(2, offset);

const writeInt16 = (value) => writeIntN(value, 2);
const readInt16 = (offset) => readInt(2, offset);

const writeUInt8 = (value) => writeIntN(value, 1);
const readUInt8 = (offset) => readUint(1, offset);

const writeInt8 = (value) => writeIntN(value, 1);
const readInt8 = (offset) => readInt(1, offset);

writeUInt32(Math.pow(2,32)-1);
writeInt32((1<<31)-1);
writeInt32(-(1<<31));
writeUInt16((1<<16)-1);
writeInt16((1<<15)-1);
writeInt16(-(1<<15));
writeUInt8((1<<8)-1);
writeInt8((1<<7)-1);
writeInt8(-(1<<7));

console.log(buffer);
console.log(readUInt32(0));
console.log(readInt32(4));
console.log(readInt32(8));
console.log(readUInt16(12));
console.log(readInt16(14));
console.log(readInt16(16));
console.log(readUInt8(18));
console.log(readInt8(19));
console.log(readInt8(20));

[
  255, 255, 255, 255, 255, 255,
  255, 127,   0,   0,   0, 128,
  255, 255, 255, 127,   0, 128,
  255, 127, 128
]
4294967295
2147483647
-2147483648
65535
32767
-32768
255
127
-128

推荐阅读