Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pack one 4-bit and two 10-bit integers into a UintArray(3), and then read them back in JavaScript?

Tags:

javascript

I'm trying to pack a 4 bit (0-15) number, followed by two 10 bit numbers (0-1023), into a UintArray(3)

Such as: 15, 1023, 1023

I am able to read the first 4 bit number, and the last 10 bit number.

But I can't seem to figure out reading/writing the middle 10 bit number

function writeInt4_10_10(arr, off, a, b, c) {
  arr[off + 0] = (a << 4) & 0xf0 | (b >> 4) & 0x0f;
  arr[off + 1] = (b << 6) & 0xfc | (c >> 8) & 0x03;
  arr[off + 2] = (c << 0) & 0xff;
}

function readInt4_10_10(arr, off) {
  var a = (arr[off + 0] & 0xf0) >> 4;
  var b = (arr[off + 0] & 0x0f) << 6 | (arr[off + 1] & 0xfc) >> 4;
  var c = (arr[off + 1] & 0x03) << 8 | (arr[off + 2] & 0xff) >> 0;
  return [a, b, c];
}

var buf = new Uint8Array(3);
writeInt4_10_10(buf, 0, 13, 1001, 999)
var r = readInt4_10_10(buf, 0);
console.log(r)
like image 537
Unwarped Avatar asked Oct 13 '25 01:10

Unwarped


2 Answers

The writing method has the wrong shift offsets. To get the highest 4 bit of the 10-bit b into the lowest 4 bits of arr[0], they need to be shifted by 6. And to get the lowest 6 bit of b into the highest 6 bit of the 8-bit arr[1], they need be shifted by 2:

function writeInt4_10_10(arr, off, a, b, c) {
  arr[off + 0] = (a << 4) & 0xf0 | (b >> 6) & 0x0f;
//                                       ^
  arr[off + 1] = (b << 2) & 0xfc | (c >> 8) & 0x03;
//                     ^
  arr[off + 2] = (c << 0) & 0xff;
}

Notice how the 6 now correspond to the shift in your reading method, where you shift by the same amount just the other direction. However the shift of the lowest 6 bits is mistaken there as well:

function readInt4_10_10(arr, off) {
  var a = (arr[off + 0] & 0xf0) >> 4;
  var b = (arr[off + 0] & 0x0f) << 6 | (arr[off + 1] & 0xfc) >> 2;
//                                                              ^
  var c = (arr[off + 1] & 0x03) << 8 | (arr[off + 2] & 0xff) >> 0;
  return [a, b, c];
}
like image 145
Bergi Avatar answered Oct 14 '25 15:10

Bergi


In short, you need this line in your write routine:

arr[off + 1] = (b & 0x3f) << 2 | (c >> 8) & 0x03;

And this line in your read routine:

var b = (arr[off + 0] & 0x0f) << 6 | (arr[off + 1] & 0xfc) >> 2;

Putting it all together.

function writeInt4_10_10(arr, off, a, b, c) {
  arr[off + 0] = (a << 4 & 0xf0) | (b >> 6 & 0x0f);
  arr[off + 1] = (b & 0x3f) << 2 | (c >> 8) & 0x03;
  arr[off + 2] = (c << 0) & 0xff;
}

function readInt4_10_10(arr, off) {
  var a = (arr[off + 0] & 0xf0) >> 4;
  var b = (arr[off + 0] & 0x0f) << 6 | (arr[off + 1] & 0xfc) >> 2;
  var c = (arr[off + 1] & 0x03) << 8 | (arr[off + 2] & 0xff) >> 0;
  return [a, b, c];
}

var buf = new Uint8Array(3);
writeInt4_10_10(buf, 0, 13, 1001, 999)
var r = readInt4_10_10(buf, 0);
console.log(r)

The problem you had is mostly in storing the data at index 1. For your numbers 13, 1001, 999, we have the following in binary:

00001101 | 1111101001 | 1111100111

And to pack into a Uint8Array as you've described we need the following arrangement:

11011111 | 10100111 | 11100111

So the issue with your code in the write routine is that you shifted b << 6 without first removing the leading 4 binary digits via a bitmask. 0x3f is the mask you want for that purpose. You only need to shift the result of & 0x3f by 2 to get those bits in the correct position.

For the read routine, you were almost there but you didn't shift the appropriate amount for var b. (arr[off + 1] & 0xfc) is the right idea, but that mask removes two digits, so you should only shift the result right by 2.

like image 21
h0r53 Avatar answered Oct 14 '25 14:10

h0r53