Juggling bits in JavaScript

Bitwise operators

| OR
& AND
^ XOR
~ NOT
>> RIGHT SHIT
<< LEFT SHIFT
>>> 0-FILL RIGTH SHIFT

[ | ] OR

logical inclusive OR operation on each pair of corresponding bits.

The result in each position is 0 if both bits are 0, while otherwise the result is 1


   0101 (decimal 5)
OR 0011 (decimal 3)
 = 0111 (decimal 7)

 

Most common usage in JavaScript

// Rounding (floor'ing)

var myFloat = 3.14;
var rounded = myFloat | 0;

[ & ] AND

Performs the logical AND operation on each pair of the corresponding bits, by multiplying them.

Thus, if both bits in the compared position are 1, the bit in the resulting binary representation is 1


    0101 (decimal 5)
AND 0011 (decimal 3)
  = 0001 (decimal 1)
 

Usage

  • bitmasks
  • (semi)complex algorithms 

[ ^ ] XOR

Performs the logical exclusive OR operation on each pair of corresponding bits. The result in each position is 1 if only the first bit is 1 or only the second bit is 1, but will be 0 if both are 0 or both are 1. 


    0101 (decimal 5)
XOR 0011 (decimal 3)
  = 0110 (decimal 6)
 

Usage

// swapping variables

var a = 5;
var b = 6;

a^=b, b^=a, a^=b;

console.log('a', a); // 6
console.log('b', b); // 5
// XOR variable swap explained:

x1 = x0 xor y0
y2 = x1 xor y0
x2 = x1 xor y2

// Substituting: 
x1 = x0 xor y0
y2 = (x0 xor y0) xor y0
x2 = (x0 xor y0) xor ((x0 xor y0) xor y0)

// Associativity and commutativity
y2 = x0 xor (y0 xor y0)
x2 = (x0 xor x0) xor (y0 xor y0) xor y0

// Since x xor x == 0 for any x,
y2 = x0 xor 0
x2 = 0 xor 0 xor y0

// And since x xor 0 == x for any x,
y2 = x0
x2 = y0

XOR swap explanation

let a = 1;

a ^= 1; // 0
a ^= 1; // 1
a ^= 1; // 0

Toggle switch

[ ~ ] NOT

Unary operation that performs logical negation on each bit, forming the ones' complement of the given binary value. Bits that are 0 become 1, and those that are 1 become 0.


NOT 0111  (decimal 7)
  = 1000  (decimal −8)
 

Usage

// Rounding (faster Math.floor() )

~~3.14; // 3

// Converts a number to -(N+1)

'rinat'.indexOf('z') // -1

~'rinat'.indexOf('z') // 0 - falsy

[ >> ] RIGHT SHIFT

Shifts bits to the right, discarding bits shifted off.


   10010111 (decimal −105) RIGHT-SHIFT
=  11001011 (decimal −53)
 

Common usage

// Division by the power of 2

8 >> 1; // 4

8 >> 2; // 2


[ << ] LEFT SHIFT

Shifts bits to the left, shifting in zeroes from the right.


   00010111 (decimal +23) LEFT-SHIFT
=  00101110 (decimal +46)

Common usage

// Multiplication by the power of 2

8 << 1; // 16

8 << 2; // 32

// Decimal to integer

3.14 << 0 // 3

[ >>>] 0-FILL RIGHT SHIFT

Shifts bits to the right, discarding bits shifted off, and shifting in zeroes from the left.


   1010100 LEFT-SHIFT
=  0001010

Common usage

// Division by the power of 2, not for negatives

8 >> 1; // 4

8 >> 2; // 2

Simple hash

String.prototype.simpleHash = function () {
    return this.split('').map(function(char){
    	return char.charCodeAt();
    }).join('');
}

HashCode()

h(s) = \sum_{i=0}^{n-1}s[i]\cdot 31^{n-1-i}

In the Java programming language, every class implicitly or explicitly provides a hashCode() method, which digests the data stored in an instance of the class into a single hash value (a 32-bit signed integer).

where terms are summed using 32-bit int addition, s[i] denotes the ith character of the string, and n is the length of s.

From Java 1.2, java.lang.String class implements its hashCode() using a product sum algorithm over the entire text of the string.

h = s[0]*31^{n-1}+s[1]*31^{n-2}+...+s[n-1]

HashCode() continued

String.prototype.hashCode = function () {
    var hash = 0;
    
    this.split('').map(function(char){
        var code = char.charCodeAt();
        hash = ((hash<<5)-hash)+code;
        hash = hash & hash; // Convert to 32bit integer
    });

    return hash;
}
((hash<<5)-hash) == ((hash * 2^{5}) - hash)

Book recomendation

Juggling with bits in JavaScript

By Rinat U

Juggling with bits in JavaScript

  • 754