Encode Int to Bytes using logical operators

Viewed 105

I've been doing some work on logical arithmetic recently. I want to encode unsigned integers (Uint's) and signed integers (Int's) as bytes.

Below is a code snippet that currently translates UInts to bytes and vice versa. Unfortunately I got some problems while encoding signed integers with my tactic.

Encoding for Integers will be performed using this shift and mask method for both - unsigned and signed integers.

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

So what is wrong with my readInt-method and how to fix this?

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?


Note: I know about the basic operations to decode 8,16-bit signed ints but how to get this inside the for loop in readUint more efficient?

Decoding 8-bit signed integers: (buffer[offset++] << 24) >> 24

Decoding 16-bit signed integers: (((buffer[offset++] << 0) | (buffer[offset++] << 8)) << 16) >> 16

1 Answers

So what is wrong with my readInt-method and how to fix this?

The fix: change (8*n) to (8*(4-n)).

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

Or, equivalently,

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 bitwise operators use 32-bit (4-byte) integers. The left shift (<<) operator discards bits shifted off to the left. The right shift operator (>>) propagates the leftmost (sign) bit.

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
Related