Bitwise Basics
Bitwise operators let one integer carry a bank of flags, permissions, or packed fields. AND tests a mask, OR sets bits, XOR toggles them, and shifts move a field into position. This lesson makes those operations predictable by aligning two unsigned 8-bit words and keeping every result inside a fixed boundary.
How Bitwise Basics Works
Picture two strips of punched tape held against the light. Each hole lines up with exactly one hole on the other strip. A Boolean bitwise operator looks through one aligned pair, decides the output for that spot, and moves to the next pair. Nothing in bit 5 can change the decision at bit 4.
That local control is the practical point. A permission byte can store eight yes-or-no flags; permissions & READ_MASK tests one flag without disturbing the other seven. Packed color or protocol fields use a mask to select positions and a shift to move the selected field where ordinary code can read it.
AND writes 1 only when both input bits are 1. OR writes 1 when either input is 1. XOR writes 1 when the two inputs differ. NOT has only one input, so it simply flips 0 to 1 and 1 to 0.
Shifts are different. Instead of choosing a new bit from aligned inputs, they move every bit to a new position. A left shift moves toward bit 7; a right shift moves toward bit 0. Bits that cross the edge disappear, and every newly vacant position receives 0.
This lesson treats values as unsigned 8-bit words. That means valid values run from 0 to 255, and the mask is 11111111. The mask after NOT and left shift keeps their results inside the same eight positions.
Bitwise Basics Step by Step
The default trace starts with a = 181 = 10110101, b = 102 = 01100110, and shift = 1. The aligned columns contain all four possible input pairs, so the run exercises every row of the AND, OR, and XOR rules.
The two rows now behave like the punched-tape strips from above: they stay clamped in the same alignment while the operator rule changes. First, AND scans from bit 7 to bit 0. Only columns where both bits are 1 survive, producing 00100100 = 36.
OR repeats the scan but accepts a 1 from either input. Its result is 11110111 = 247.
XOR writes 1 only for mismatched pairs. Equal pairs become 0, giving 11010011 = 211.
NOT ignores b and flips every bit of a. Inside the 8-bit mask, 10110101 becomes 01001010 = 74.
Then the safety rail comes off for one beat. In both Python and JavaScript, raw ~181 is -182. The expression -182 & 0b11111111 is not a special cleanup operator; it is the same AND rule you just learned. The eight low positions survive, every position outside the word is cleared, and the result returns to 01001010 = 74.
For the left shift, every bit of a moves one position toward bit 7. The original bit 7 crosses the boundary, bit 0 is filled with 0, and the masked result is 01101010 = 106.
For the right shift, every bit moves one position toward bit 0. The original bit 0 is discarded, bit 7 is filled with 0, and the result is 01011010 = 90.
The result ledger keeps all six answers visible. This makes the main contrast hard to miss: Boolean operators make local decisions in fixed columns, while shifts move bit positions and can lose information at the boundary.
Time and Space Complexity
For the fixed 8-bit values used here, each machine operator takes constant time and constant extra space: O(1) time and O(1) space.
The animation deliberately visits each bit so the rule is visible. If the word width is called W, that explanatory scan takes O(W) time per Boolean operator. In languages with arbitrary-width integers, the real cost of a bitwise operation can also grow with the number of machine words needed to hold the value.
Edge Cases
- If
shift = 0, no bit moves, no bit is discarded, and no zero-fill slot is needed. - If
shift = 8, every source bit leaves the word. Both shift results are00000000. - If
aandbare equal, XOR produces all zeros while AND and OR both reproduce the input. - If
aandbare complements, AND produces all zeros, OR produces all ones, and XOR also produces all ones. a = 0anda = 255show the two extremes of the 8-bit range. NOT swaps those extremes.
Common Mistakes
A left shift is often described as multiplication by two, and a right shift as division by two. That shortcut only works when you also account for the word boundary and the number model. In this lesson, a high bit discarded by a left shift cannot be recovered, so the result may not equal ordinary integer multiplication.
Another common mistake is expecting shifted bits to wrap around to the other side. Ordinary << and >> do not rotate. Bits that cross the boundary are gone, while the empty positions receive zeros.
NOT is especially easy to misread in Python because Python integers are not limited to eight bits. With the default input, ~181 is -182, not 74. Applying & MASK performs AND with 255, selects the low eight bits, and restores the unsigned word used here.
Finally, bit indices and display positions run in opposite visual directions: bit 7 is on the left and bit 0 is on the right. The labels above the cells are the authority when tracking a shift.
A Note on Simplification
Real processors usually operate on 8-, 16-, 32-, or 64-bit machine words, and programming languages differ in how they represent signed values and perform right shifts. This lesson fixes one unsigned 8-bit model so the operator rules stay visible. Its right shift always fills with zero; it does not model arithmetic right shift or sign extension.
Keep exploring
A few lessons that share the same technique or lead into the next idea.
Premium players need paid access. Every Explain doc is free.
Found a mistake or something unclear? Leave feedback.