2

I have an array:

[43, 44, 45, 46, 47, 2]

And I need to convert it to one 32 bit unsigned integer. So the first 5 values each use 6 bits and the last value uses 2 bits.

On C this code looks like:

 varToPack = (array[0] &0x3F) +
              ( (array[1]<<6) &0x3F) +
              ( (array[2]<<12) &0x3F) +
              ( (array[3]<<18) &0x3F) +
              ( (array[4]<<24) &0x3F) +
              ( (array[5]<<30) &3)

I want to do the same on JS, I did and it works:

let varToPack = arr[0]+
(arr[1]<<6)+
(arr[2]<<12)+
(arr[3]<<18)+
(arr[4]<<24)+
(arr[5]<<30);

But only when the last value in array[5] will be 0 or 1. After I set last value to 2 I get negative number. So according to this answer:

Bitwise operations on 32-bit unsigned ints?

I did the following modification:

let varToPack = arr[0]+
(arr[1]<<6)+
(arr[2]<<12)+
(arr[3]<<18)+
(arr[4]<<24)+
((arr[5]<<30)>>>0);

This works, but in sum it returns value gather then 2147483648, because I didn't use &0x3F that won’t let the number be greater than 6bits.

But when I do:

let varToPack = (arr[0]&0x3F)+
                ((arr[1]<<6)&0x3F)+
                ((arr[2]<<12)&0x3F)+
                ((arr[3]<<18)&0x3F)+
                ((arr[4]<<24)&0x3F)+
                (((arr[5]<<30)>>>0)&3);

It returns 0. What am I doing wrong ?

Kevin
  • 6,993
  • 1
  • 15
  • 24
Arti
  • 7,356
  • 12
  • 57
  • 122
  • 1
    In C, `(array[4]<<24) &0x3F)` will always evaluate to zero - the right-most 24 bits after you left-shift `array[4]` by 24 bits will always be zero, then you bitwise-and that result with `0x3F`, where only the right-most seven bits are non-zero. Hence, always zero. I suspect javascript is the same, but I don't know, so this is just a comment. You probably want `( ( array[4] & 0x3F ) << 24 )` – Andrew Henle Nov 29 '18 at 14:58
  • 1
    "I need to convert it to one 32 bit unsigned integer." "I get negative number" This doesn't make any sense. – Lundin Nov 29 '18 at 15:22
  • @Lundin :) yes, it is shame:) Never went deep into this before – Arti Nov 29 '18 at 15:30

2 Answers2

1

The reason this isn't working:

let varToPack = (arr[0]&0x3F)+
                ((arr[1]<<6)&0x3F)+
                ((arr[2]<<12)&0x3F)+
                ((arr[3]<<18)&0x3F)+
                ((arr[4]<<24)&0x3F)+
                (((arr[5]<<30)>>>0)&3);

Is because you first shift each value, then perform a logical AND. Since the bits you want have been shifted out of the positions specified by the AND, everything gets masked out. You want to mask the values, then shift them. Also, use a logical OR instead of addition, as that more accurately reflects what you're actually doing.

let varToPack = (a[0] &0x3F) |
              ( (a[1] & 0x3f) <<6) |
              ( (a[2] & 0x3f) <<12) |
              ( (a[3] & 0x3f) <<18) |
              ( (a[4] & 0x3f) <<24) |
              (( (a[5] & 0x3) <<30) >>> 0);

As for the negative value, Javascript performs all bitwise operations on 32-bit signed values (the result of which is then converted to a 64-bit float), so it's not surprising that the result is negative.

The values you stored are however present in the resulting variable. If you extract out the bits from the value in question, you'll get back the original values:

let b = [];
b[0] = varToPack & 0x3f;
b[1] = (varToPack >>> 6) & 0x3f;
b[2] = (varToPack >>> 12) & 0x3f;
b[3] = (varToPack >>> 18) & 0x3f;
b[4] = (varToPack >>> 24) & 0x3f;
b[5] = (varToPack >>> 30) & 0x3;
dbush
  • 205,898
  • 23
  • 218
  • 273
1

Bitwise operators in JavaScript are unfortunately limited to 32-bit signed integers.

You can't "pack" your input into a 32-bit signed integer since 2 * 230 exceeds it. The maximum positive signed 32-bit integer is 231 - 1.

If you want to pack it into a 64-bit integer instead, you can multiply the 6th element by 230 to avoid a 32-bit signed integer overflow:

let arr=[43, 44, 45, 46, 47, 2];

let varToPack =  arr[0] + 
                (arr[1]<<6) +
                (arr[2]<<12) +
                (arr[3]<<18) +
                (arr[4]<<24) +
                (arr[5]*(1<<30));

document.getElementById("result").innerHTML = varToPack;
Result: <span id="result">
rustyx
  • 80,671
  • 25
  • 200
  • 267