Bitwise Operators and Binary Numbers Explained in Javascript

Steve Pesce
6 min readJul 27, 2020

Binary Numbers from a Decimal Perspective

Decimal numbers have a base of 10, meaning that any decimal number can be represented as the sum of powers of 10.

And in summation form:

This is a summation symbol. Think of it as a for loop, where ‘i’ is the counter, n is the exit condition, and x are each elements of a distinct array. Each pass, this sum would be added to a variable until we have a final result.

So we can represent, for example, the number 130 as a sum as such:

or

And in summation form:

Binary numbers have a base of 2, meaning that any binary number can be represented as the sum of powers of 2.

And in summation form:

In fact, you can use this same formula to express any number of any base:

This might seem confusing. The upside-down ‘A’ means for all, the epsilon means in the set, the N is a natural number. Everything before the summation symbol is only adding constraints to all of the variables that they must be a positive integer (or zero). x_i are the digits of the number; b is the base; i is the current index; n is the last index.

Any base can be shown in this form by simply changing base b. You can apply this formula to a hexadecimal number to find its decimal value:

Hexadecimal summation in decimal

It takes many more digits to represent a number in binary than in decimal, but the summation is more simple. x can only ever be 1 or 0, you either add the power of 2 or dont, whereas in a decimal number, every power of 10 is multiplied by any number from 0..9. For this reason we can drop the x variable and only sum up powers that are present.

When converting numbers to binary, it might be useful to memorize the powers of two. Even without experience in binary arithmetic, you may recognize some of these numbers as common memory/storage sizes.

So we can represent that same number (130) as:

Binary numbers are simple in that we only add one base of 2 or dont. Imagine this example like a reduce loop, where the array is [1,7] and i is the element, and each pass is added to the result.

Or in long form:

So now we can represent this as(note: 2 denotes base 2 aka binary):

Each digit represents the presence (1) or non-presence(0) of that power of 2.

Boolean Algebra

A bitwise operators &(AND), |(OR), ^(XOR), and ~(NOT) are operations used in boolean algebra. They are logical operators that compare variables that can only have two discrete values: true or false. I like to visualize them as functions:

Here are these operators represented by a truth table as well as their corresponding logic gates (note: T is represented as 1, F is represented as 0):

These are logic gates. Don’t worry about their structure, just note the number of inputs and outputs.

Bitwise Operations

A Bitwise operation is just an operation that is performed bit by bit.

To do the operation 111010 AND 101010, you would compare each bit — 101010, because the second digit was the only digit not the same as the other.

You may be thinking that there is no binary number class in Javascript. There is not, but all numbers in computer programs are stored in memory as binary numbers. The bitwise operations are used on numbers, so this means that even though we are dealing with binary operations, the numbers that we use are represented in decimal.

The result (42) is the same number that we used in our expression. This actually makes sense — the first number has a 1 in every digit that the second number has a 1, but the second number does not have a 1 in every digit that the first number has a 1. Here is our result as a sum of powers of 2:

Or we can check it in Javascript:

sidenote: this method does not worked with signed numbers.

Bitwise Shift Operators

The operators ‘<<’ ‘>>’ and ‘>>>’ all work similar to an array shift/unshift. They push digits up or down the number. You must specify a number of digits to shift.

Zero fill left shift (<<) pushes zeroes from the right side, shifting everything ahead of it left by one place for each shift. The number of digits cannot exceed 32, so if there are 32 digits, the left most digit will be lost on every shift.

Signed right shift (>>) pushes copies of the leftmost bit to the right, bits at the right are lost.

Note that I am using a function defined elsewhere to check the number, this is because, as I stated before, signed numbers can not be converted to binary with toString(2).

A signed (stored as positive or negative) number’s left most bit is always 1 when negative and 0 when positive. The 1 that is copied over above is 32nd bit to the left, not the 1 that you see as the first number of signedRs. The following example, using a positive number, demonstrates this. A positive signed number’s first bit is always 0, which you do not see in signedPositive:

Had it been the left-most digit in our displayed number, it would have copied over ones, instead it copied over zeroes, which are just left out since they are insignificant now (in decimal you wouldn’t say 00002, just 2).

Zero Fill Right Shift (>>>) pushes in zeroes from the left. The right digits will be replaced. So this should give the same result as signed right shifting signedPositive. Lets see:

Why Use Bitwise Operators

A simple answer would be that you may not, in practice. Bitwise operations are incredibly efficient, but they make code harder to understand. For the same reason that we strive to create higher level programming languages, we tend to sacrifice small performance benefits for readability.

If you are interested in finding uses for bitwise operations in Javascript consider this Stack Overflow question where users talk about applying them to things like for hex to RBG, IP calculations, or a more efficient version of isOdd().

--

--