Bit Shift Explained: Why Left Shifts Double and Right Shifts Halve
A practical guide to bit shift operations — left and right shifts, why a left shift multiplies by two, arithmetic versus logical right shifts, and flags.
Bit Shift Explained: Why Left Shifts Double and Right Shifts Halve
Bit shifting is one of those operations that feels like magic until the moment it clicks, and then it feels obvious. You move the bits of a number left or right by some number of positions, zeros stream in on one side, bits fall off the other, and somehow the value doubles or halves. This guide walks through what is actually happening under the hood, why a left shift multiplies by a power of two, how signed and unsigned right shifts differ, and where shifts earn their keep in real code.
If you want to follow along and watch the bits move, open the Bit Shift Calculator in another tab. Type a value, pick a shift type and amount, and it lays the binary out in 4-bit groups so you can see exactly which bits arrive and which fall away.
What a Shift Actually Does
A binary number is a row of bits where each position carries a fixed weight: the rightmost bit is worth 1, the next is worth 2, then 4, 8, 16, and so on, doubling each step to the left. A shift slides every bit a fixed number of positions sideways.
Shift left by n, written x << n, moves every bit toward the high end and pads the vacated low positions with zeros. Shift right by n, written x >> n or x >>> n, moves every bit toward the low end and the lowest bits drop off the end entirely.
That is the whole mechanism. Everything else — the doubling, the halving, the sign behavior — falls out of what those position weights mean once the bits land in new slots.
Why Left Shift Multiplies by Two
Here is the concrete rule worth memorizing: x << n multiplies x by 2 to the power n, so x << 1 doubles, x << 2 quadruples, and x << 3 multiplies by eight.
The reason is the position weights. When you push a bit one place to the left, the bit that was worth 1 lands in the slot worth 2. The bit worth 2 lands in the slot worth 4. Every set bit's contribution exactly doubles, so the whole number doubles. Shift by two positions and each weight quadruples, which is multiplying by 4, or 2 squared. In general, shifting left by n multiplies by 2^n.
Let me work a real example. Take the decimal number 5 and shift it left by 2:
5 = 0000 0101 (4 + 1)
5 << 2 = 0001 0100 (16 + 4) = 20
Every bit moved two slots toward the high end, two zeros filled the low slots, and 5 became 20 — exactly 5 multiplied by 2 squared. Now run it back the other way with a right shift:
20 = 0001 0100 (16 + 4)
20 >> 1 = 0000 1010 (8 + 2) = 10
One right shift dropped the lowest bit, every weight halved, and 20 became 10. That is the symmetry: left shift by one doubles, right shift by one halves.
Signed Versus Unsigned: Arithmetic and Logical Right Shifts
Left shifts are simple because you always fill with zeros. Right shifts have a fork in the road, and it is the part that bites people. The question is what fills the high bits that open up when everything slides right.
In a fixed width — say 8, 16, or 32 bits — the top bit is the sign bit under two's complement. A 1 there means the number is negative. So when bits move right, what should appear in the freshly vacated top slot?
Arithmetic right shift (>>) copies the sign bit back into the top. A negative number stays negative, a positive number stays positive, and the value floor-divides by two. This is the right choice for signed integers.
Logical right shift (>>>) ignores the sign entirely and always pads with zeros. It treats the bit pattern as a raw unsigned value. The crucial property: arithmetic right shift preserves the sign bit, while logical right shift discards it.
For non-negative numbers the two agree completely — there is no sign bit set, so copying it or zero-filling both put a zero on top. The split only shows up once the high bit is 1. In 8-bit, the value -8 is the pattern 1111 1000:
-8 >> 1 (arithmetic) = 1111 1100 = -4 (sign copied in)
-8 >>> 1 (logical) = 0111 1100 = 124 (zero filled in)
Same input, same direction, wildly different answers. Reach for >> when the value is a signed integer you want to keep dividing correctly, and reach for >>> when the value is conceptually unsigned bytes, color channels, or a bag of flags where the top bit carries no sign meaning.
One subtlety worth flagging: arithmetic right shift floors toward negative infinity, it does not truncate toward zero. So -7 >> 1 is -4, not -3, because floor(-3.5) is -4. When you port shift code into a language whose integer division truncates, that off-by-one on negatives is a classic silent bug.
Where Shifts Earn Their Keep
Shifting is not academic. Three places where it shows up constantly:
Flags and bitmasks. Feature flags live as single bits: 1 << 0, 1 << 1, 1 << 2, each one a different power of two so they never collide. To test whether a flag is set you mask with a bitwise AND; to set one you OR it in. The companion bitwise calculator is handy when you need to combine the AND, OR, and XOR steps that pair with these shifts. Count from 1 << 0, not 1 << 1 — the first flag is bit zero, and starting at one doubles every mask.
Cheap multiply and divide. On hardware without a fast divider, x << 3 replaces a multiply by eight and x >> 1 replaces a halving. Compilers do this automatically, but on a microcontroller, or in a hot loop where you control the width, knowing the shift maps cleanly to a power of two lets you reason about cost and overflow directly.
Packing and unpacking fields. A 32-bit color crams four 8-bit channels together. To build one you shift each channel into place (red << 24, green << 16, blue << 8); to read one back you shift right and mask. Protocol headers do the same with version, length, and flag fields squeezed into a single word.
I keep the calculator open whenever I touch a packed format. Last week I was unpacking a 16-bit header where a 4-bit version sat above a 12-bit length, and I had talked myself into shifting right by 11 instead of 12. Pasting the raw word in and watching the binary realign by one position made the mistake obvious in a way that staring at the source never did. If you would rather see the same value side by side in decimal, hex, and binary while you reason about it, the base converter covers that pairing too.
Watch Out for Overflow
One last trap. Each width has a fixed number of slots, and a left shift that pushes bits past the top simply drops them. In 8-bit, 200 << 1 does not give 400 — the high bit falls off and the result wraps. Left shift can even push a 1 into the sign position and flip a positive number negative: in 8-bit, 64 << 1 lands on -128. Always set the width that matches your target register before reading a shifted result, and move up to 16 or 32 bits when you need the headroom. Tools that mask to your chosen width show you exactly what a real register would hold, dropped bits and all.
Made by Toolora · Updated 2026-06-13