I was solving a puzzle the other day and it involved a relatively simple function
ƒ(x,y) = 5x-y · 10y

Using a little bit of algebra, we can simplify this a little
5x-y · 10y =  5x · 5-y · 5y · 2y = 5x · 2y

In JavaScript, this could be expressed like this

(x, y) => 5 ** x * 2 ** y

While doing a little bit of research on the puzzle I was trying to solve, I ended up on the MDN Bitwise Operator page where we can read that

Bitwise shifting any number x to the left by y bits yields x * 2 ** y.

Humm... where have I seen this kind of function recently? This means that we could now rewrite our JavaScript function this way

(x, y) => 5 ** x << y

Interesting, but how does that work and why would you possibly prefer the use of the left shift bitwise operator over the regular math syntax?

How does it work

Lets unpack the statement that shifting any number x to the left by y bits is the same as multiplying x by 2 to the power of y. And enough with all those x's and y's, let's use real numbers.

3 * 2 ** 4

You should be able to work out the solution to the above by hand or in your head. 2 to the power of 4, or if your prefer 2 * 2 * 2 * 2 = 16, and 3 * 16 = 48. Why does feeding JavaScript 3 << 4 give us the same result? It all has to do with the '2 to the power of 4' portion of the equation. Let's work through our 2 to the power of 4 again.

2 * 2 * 2 * 2 = 16
2 * 2 = 4
    4 * 2 = 8
        8 * 2 = 16

If you know a little bit about the binary numeral system you'll have recognized that all of these totals actually represent the value of different positions in the base-2 system.

128 64 32 [16] [8] [4] 2 1

If you're not familiar with the binary numeral system, I highly recommend you go through Khan Academy's excellent video series on the topic. Go ahead, I'll wait.

Once you realize this, it's easy to see what is going on. If we take the number 3 and represent it in binary

128 64 32 16 8 4 2 1
  0  0  0  0 0 0 1 1

and then left shift our bits by 4 positions

128 64 32 16 8 4 2 1
  0  0  1  1 0 0 0 0

we get the number 48. So now we understand how the left shift operator works but we may still not fully understand why this gives us the same result as 3 * 2 ** 4. To help us understand it could be useful to do the same kind of operation but using the decimal system since we are much more familiar with it. So instead of doing 3 * 2 ** 4 lets try doing 3 * 10 ** 4, the result of which is 30,000, but let's not get ahead of ourselves. First, let's represent 3 in our decimal system.

100000 10000 1000 100 10 1
     0     0    0   0  0 3

Now let's shift left by 4 digits

100000 10000 1000 100 10 1
     0     3    0   0  0 0

BOOM! 30,000. Now do you get it? Left shifting by one position in any numeral system is the equivalent of multiplying by the radix, or the base, of that numeral system. Still not convinced, let's try it again, this time with the hexadecimal system or base-16. Let's do 3 * 16 ** 4 which results in 196,608. First, we represent the number 3 in base-16.

1048576 65536 4096 256 16 1
      0     0    0   0  0 3

Then we apply our left shift.

1048576 65536 4096 256 16 1
      0     3    0   0  0 0

What do we get? Well 3 x 65,536 is... that's right, 196,608. So what's the takeaway? That whenever we have operations in our code that multiply a number by 2 to the  power of whatever (including to the power of 1), we can instead choose to use the left shift bitwise operator. But why would you chose to do that?

Why (not to) use the left shift operator

Honestly, you probably wouldn't. I couldn't find a good reason to use the left shift operator instead of simple multiplication. Performance is normally the main reason why a programmer would choose to use bitwise operations over simple math operations. But in fact, according to this interesting article, and my own tests, it's actually a tiny bit slower, in JavaScript, to use the left shift operator.

Bitwise operations are a bit harder to read and understand for most programmers and if there is nothing to be gained in terms of performance by using them, then one should really consider using regular math operations instead.