a_here_and_now
a_here_and_now

Reputation: 187

Converting a Two's complement number to its binary representation

I am performing bitwise operations, the result of which is apparently being stored as a two's complement number. When I hover over the variable it's stored in I see- num = -2086528968.

The binary of that number that I want is - (10000011101000100001100000111000).

But when I say num.toString(2) I get a completely different binary representation, the raw number's binary instead of the 2s comp(-1111100010111011110011111001000).

How do I get the first string back?

Link to a converter: rapidtables.com/convert/number/decimal-to-binary.html Put in this number: -2086528968

Upvotes: 1

Views: 1292

Answers (2)

Thomas
Thomas

Reputation: 12637

pedro already answered this, but since this is a hack and not entirely intuitive I'll explain it.

I am performing bitwise operations, the result of which is apparently being stored as a two's complement number. When I hover over the variable its stored in I see num = -2086528968

No, the result of most bit-operations is a 32bit signed integer. This means that the bit 0x80000000 is interpreted as a sign followed by 31 bits of value.

The weird bit-sequence is because of how JS stringifies the value, something like sign + Math.abs(value).toString(base);

How to deal with that? We need to tell JS to not interpret that bit as sign, but as part of the value. But how?

An easy to understand solution would be to add 0x100000000 to the negative numbers and therefore get their positive couterparts.

function print(value) {
  if (value < 0) {
    value += 0x100000000;
  }
  console.log(value.toString(2).padStart(32, 0));
}

print(-2086528968);

Another way would be to convert the lower and the upper bits seperately

function print(value) {
  var signBit = value < 0 ? "1" : "0";
  var valueBits = (value & 0x7FFFFFFF).toString(2);

  console.log(signBit + valueBits.padStart(31, 0));
}

print(-2086528968);


//or lower and upper half of the bits:
function print2(value) {
  var upperHalf = (value >> 16 & 0xFFFF).toString(2);
  var lowerHalf = (value & 0xFFFF).toString(2);
  console.log(upperHalf.padStart(16, 0) + lowerHalf.padStart(16, 0));
}

print2(-2086528968);

Another way involves the "hack" that pedro uses. You remember how I said that most bit-operations return an int32? There is one operation that actually returns an unsigned (32bit) interger, the so called Zero-fill right shift.

So number >>> 0 does not change the bits of the number, but the first bit is no longer interpreted as sign.

function uint32(value){
  return value>>>0;
}

function print(value){
  console.log(uint32(value).toString(2).padStart(32, 0));
}

print(-2086528968);

will I run this shifting code only when the number is negative, or always?

generally speaking, there is no harm in running nr >>> 0 over positive integers, but be careful not to overdo it.

Technically JS only supports Numbers, that are double values (64bit floating point values). Internally the engines also use int32 values; where possible. But no uint32 values. So when you convert your negative int32 into an uint32, the engine converts it to a double. And if you follow up with another bit operation, first thing it does is converting it back.

So it's fine to do this like when you need an actual uint32 value, like to print the bits here, but you should avoid this conversion between operations. Like "just to fix it".

Upvotes: 4

pedro.olimpio
pedro.olimpio

Reputation: 1498

Follow bellow the result:

var number = -2086528968;
    
    var bin = (number >>> 0).toString(2)
    //10000011101000100001100000111000
    console.log(bin)

Upvotes: 3

Related Questions