Gray Code Explained: One Bit at a Time, From Binary and Back
How Gray code keeps a single bit changing between neighbours, the gray = n XOR (n>>1) formula, a worked decimal example, and why rotary encoders depend on it.
Gray Code Explained: One Bit at a Time, From Binary and Back
Count up in ordinary binary and watch what happens between 3 and 4: 011 becomes 100, and three bits flip in the same instant. If a circuit reads the value mid-flip, it can latch anything from 000 to 111. Gray code was built to kill that moment. In Gray code, also called reflected binary code, any two consecutive values differ in exactly one bit. Nothing ever flips three bits at once, so a mistimed read is off by at most one step instead of landing on a wild garbage number.
That single property is the whole reason Gray code exists, and it explains why it shows up in rotary encoders, Karnaugh maps, and analog-to-digital converters. This post walks through what the code actually is, the one-line formula that produces it, a full worked example, and why decoding takes a different operation than encoding.
What Gray code looks like
Here is the first eight values, side by side with plain binary:
| Decimal | Binary | Gray | |---------|--------|------| | 0 | 000 | 000 | | 1 | 001 | 001 | | 2 | 010 | 011 | | 3 | 011 | 010 | | 4 | 100 | 110 | | 5 | 101 | 111 | | 6 | 110 | 101 | | 7 | 111 | 100 |
Read the Gray column top to bottom and check each step against the one above it. From 000 to 001, the last bit changes. From 001 to 011, the middle bit changes. From 011 to 010, the last bit again. Every single transition moves exactly one digit. That is the contract Gray code makes, and the plain binary column breaks it constantly, three bits at the 3-to-4 boundary alone.
The name "reflected" comes from how the table is built. Take the Gray sequence for two bits (00, 01, 11, 10), mirror it, prefix the first half with 0 and the mirrored half with 1, and you have the three-bit sequence. Each doubling reflects the previous block, which is a tidy way to see the structure but a slow way to convert a single number.
The one formula that matters
For converting an arbitrary number you do not need the reflection trick. There is a direct, concrete rule:
gray = n ^ (n >> 1)
Take the number, shift it right by one bit, and XOR the two together. That single expression turns any non-negative integer into its Gray code. It works because the XOR captures exactly where adjacent binary bits disagree, and those disagreement points are precisely the positions that change as you count.
In C, Rust, Python, or JavaScript it is one line:
const toGray = (n) => n ^ (n >> 1);
No lookup table, no loop, no reflection. That compactness is why hardware loves it too: a Gray encoder is just a row of XOR gates wired between adjacent bit lines.
A worked example: decimal 5 to Gray code
Let me run the formula by hand, because seeing the bits move is what makes it stick. I want the Gray code of decimal 5.
- Write 5 in binary:
101. - Shift right by one:
101 >> 1drops the low bit and gives010(decimal 2). - XOR the two:
101 ^ 010.
XOR compares bit by bit and outputs 1 only where the bits differ:
1 0 1
^ 0 1 0
-------
1 1 1
So the Gray code of 5 is 111, which read as plain binary is decimal 7. That is the answer I expect, and 5 to 111 is the test case I always reach for when I am sanity-checking someone else's encoder. The first time I reviewed a colleague's "Gray code" routine, it returned 101 for an input of 5, which is just the original binary printed straight back. The n >> 1 shift and the XOR had been quietly dropped. Dropping decimal 5 into a known-good converter and watching it return 111 caught the bug in about ten seconds, long before it reached the encoder driver where it would have been miserable to trace.
You can reproduce the whole table above and check any value yourself in the Gray Code Converter. Type a decimal, read the Gray code, then flip the direction and decode it back to confirm the round trip is exact.
Decoding is not the same operation
Here is the trap that bites people: decoding Gray code back to binary is not the encode formula run in reverse. Encoding is one shift and one XOR. Decoding XORs each bit with all the higher bits to its left, an accumulating sweep:
binary[msb] = gray[msb]
binary[i] = binary[i+1] ^ gray[i]
Take our 111. The top bit stays 1. The next bit is 1 ^ 1 = 0... wait, work it from the most significant end: 1, then 1 ^ 1 = 0, then 0 ^ 1 = 1, giving 101, which is decimal 5. The round trip closes exactly. Reusing the encode formula n ^ (n >> 1) to decode produces wrong answers for any value above 1, which is the single most common Gray code mistake I see. A converter that offers a true Gray-to-decimal direction handles this sweep for you instead of pretending one XOR does both jobs.
Why rotary encoders insist on it
The textbook home for Gray code is the absolute rotary encoder. The disc is etched with concentric tracks, one per bit, and a read head samples all tracks at once to report an angular position. With plain binary tracks, the boundary between two positions can have several track edges nearly aligned, and a head sitting on that seam may read some bits as old and some as new. The result is a momentary position that is wildly wrong, the digital equivalent of the 3-to-4 three-bit flip.
Etch the disc in Gray code and that failure mode disappears. Between any two adjacent positions exactly one track edge moves, so the worst a misaligned head can do is report the position one step early or one step late. Off by one is recoverable and small. Off by a large jump can crash a motion controller. The same logic carries into state machines, error-reducing data transmission, and some ADC ramp comparators: anywhere a one-bit slip is far cheaper than a multi-bit glitch, Gray code earns its keep.
Bit width matters here. The Gray code of 8 is 1100 and needs four bits, so an encoder word has to be wide enough for the largest position it will ever report. If you are juggling field widths across registers, ports, and encoder words, a general base converter is handy for lining up hex, binary, and decimal views of the same value before you commit a width.
The short version
Gray code is one idea applied relentlessly: never let more than one bit change at a time. Encode with gray = n ^ (n >> 1), decode with the accumulating XOR sweep, and remember they are different operations. Decimal 5 becomes 111 and decodes cleanly back to 101, the test case that catches most broken implementations. Wherever a sampling glitch is expensive, from encoder discs to Karnaugh map headers, that one-bit guarantee is doing quiet, essential work.
Made by Toolora · Updated 2026-06-13