Zac Uwyo H
Zac Uwyo H

Reputation: 147

Invert unsigned arbitrary binary bits in javascript

For instance, 10100 would be inverted to 01011; 010 would be inverted to 101; 101 would be converted to 010.

The problem is when I use ~5, it becomes -6 because js uses 32 bit signed.

How do I invert an unsigned arbitrary-bit binary number?

I would like to create a function that takes in this unsigned arbitrary-bit binary number and return its inverted form( 101->010)

I want to convert from string 101 to 010

Upvotes: 9

Views: 11491

Answers (8)

This takes a string of binary digits and returns the inverse. If the string has leading 0s they will also become 1s.

const inverseBin = bin => bin.replace(/0|1/g, bit => +!+bit);

Upvotes: 0

H S W
H S W

Reputation: 7129

For Integer values, you can use the javaScript program to reverse the order of the bits in a given integer and as a result return new integer as described below:

function binaryReverse(value) {
  return parseInt(value.toString(2).split('').reverse().join(''), 2);
}

console.log(binaryReverse(25));
console.log(binaryReverse(19));

Output:

 19
 25

Upvotes: 0

Sujeet
Sujeet

Reputation: 3810

You can create a mask for number's width and take xor to flip the bits.

/**
 * @param {number} num
 * @return {number}
 */
var findComplement = function(num) {
    let len = num.toString(2).length;
    let mask = Math.pow(2, len) - 1;
    return num ^ mask;
};
console.log(findComplement(5));

Upvotes: 0

RobG
RobG

Reputation: 147413

You can use a function that converts numbers to binary as a string, flips the 0s and 1s, then converts back to a number. It seems to give the expected results, but looks pretty ugly:

function flipBits(n) {
  return parseInt(n.toString(2).split('').map(bit => 1 - bit).join(''),2)
}

[0,1,2,3,4,5,123,987679876,987679875].forEach(
   n => console.log(n + ' -> ' + flipBits(n))
);

Maybe there's a mix of bitwise operators to do the same thing.

Edit

It seems you're working with strings, so just split, flip and join again:

// Requires support for ECMAScript ed 5.1 for map and 
// ECMAScript 2015 for arrow functions
function flipStringBits(s) {
  return s.split('').map(c => 1 - c).join('');
}

['0','010','110','10011100110'].forEach(
  v => console.log(v + ' -> ' + flipStringBits(v))
);

Basic function for ECMAScript ed 3 (works everywhere, even IE 4).

function flipStringBitsEd3(s) {
  var b = s.split('')
  for (var i = 0, iLen = b.length; i < iLen; i++) {
    b[i] = 1 - b[i];
  }
  return b.join('');
}

// Tests
console.log('Ed 3 version');
var data = ['0', '010', '110', '10011100110'];
for (var i = 0, iLen = data.length; i < iLen; i++) {
  console.log(data[i] + ' ->\n' + flipStringBitsEd3(data[i]) + '\n');
}

Works with any length string. The ed 3 version will work everywhere and is probably faster than functions using newer features.

Upvotes: 0

Jaromanda X
Jaromanda X

Reputation: 1

You can create a function that flips the required number of digits like so

    var flipbits = function (v, digits) {
        return ~v & (Math.pow(2, digits) - 1);
    }
    console.log(flipbits(5, 3)); // outputs 2
    console.log(flipbits(2, 3)); // outputs 5

note - this isn't "arbitrary number of bits" ... it's 32 at best

working with strings, you can have arbitrary bit length (this one wont work without transpiling in Internet Exploder)

    var flipbits = str => str.split('').map(b => (1 - b).toString()).join('');

    console.log(flipbits('010')); // outputs 101
    console.log(flipbits('101')); // outputs 010

The above in ES5

    var flipbits = function flipbits(str) {
      return str.split('').map(function (b) {
        return (1 - b).toString();
      }).join('');
    };

    console.log(flipbits('010')); // outputs 101
    console.log(flipbits('101')); // outputs 010

Upvotes: 11

guest271314
guest271314

Reputation: 1

You can use String.prototype.replace() with RegExp /(0)|(1)/

function toggle(n) {
  return n.replace(/(0)|(1)/g, function(m, p1, p2) { return p2 ? 0 : 1 });
}
    
console.log(
  toggle("10100"),
  toggle("101")  
)

Upvotes: 0

Ibu
Ibu

Reputation: 43820

In JavaScript, ~ or tilde does this

-(N+1)

So your current operation is correct but not what you are looking for:

~5
-(5 + 1)
-6

Reference

Upvotes: 0

Liam Gray
Liam Gray

Reputation: 1129

Inverting the bits will always be the same, but to convert an unsigned integer to a signed integer you can use the unsigned >>> shift operator to work on unsigned numbers:

console.log(~5);     // -6
console.log(~5>>>0); // 4294967290

If you want to make sure you only flip the significant bits in the number, you'll instead want to mask it via an & operation with how many significant bits you need. Here is an example of the significant bit masking:

function invert(x) {
  let significant = 0;
  let test = x;

  while (test > 1) {
    test = test >> 1;
    significant = (significant << 1) | 1;
  }

  return (~x) & significant;
}

console.log(invert(5));  // 2 (010 in binary)

Upvotes: 8

Related Questions