skip to Main Content

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)

2

Answers


  1. 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];
    }
    
    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search