← all experiments

One Bit at a Time

Experiment № 100 · October 25, 2026

Watch it

Disc is printed in

—
Binary
Trace
Repeat
—— —— ——
—— —— —— —
// Gray 1947, the reflected binary code
list(1) = 0, 1
list(k+1) = 0·list(k), then 1·list(k) reversed
gray(i) = i XOR (i >> 1)
decode: XOR together g, g>>1, g>>2, …
move k: the bit that flips is k's lowest 1

—

Experiment № 100 · The story

One Bit at a Time

Why I picked it

A hundredth piece felt like it should be about counting, and this is the strangest way to count I know. Frank Gray at Bell Labs filed it in 1947 as a "reflected binary code" for pulse-code communication, though Émile Baudot was already using it in telegraphs in the 1870s and Louis Gros used it in 1872 to solve the Chinese rings puzzle. It's a way of listing every number so that each one differs from the last in a single bit. That sounds like a curiosity until you hold a rotary encoder, the knob inside a volume dial or a robot joint that has to say where it's pointing. Light shines through rings of slots and a row of sensors reads them, but no row of sensors is ever perfectly straight. In plain binary, the step from 7 to 8 flips four rings at once, and a sensor that's a hair early reads 15 for an instant. Gray's code makes that impossible. For the record, 100 is 1100100 in binary and 1010110 in Gray.

What I enjoy about it

The construction is a mirror. Take the list, reflect it, put 0 on the top half and 1 on the bottom. Across the fold the two halves are identical, so the new bit is the only thing that changes there, and you can watch it happen in the first view. Then it turns out the Tower of Hanoi has been doing the same thing all along. On move k you shift the disk numbered by k's lowest 1 bit, which is exactly the bit a Gray counter flips at step k. I didn't believe that the first time I read it, so the third view runs both side by side. My favourite moment is the Encoder view in plain binary at full misalignment, where the trace below the disc sprays pink spikes halfway across the dial. Switch to Gray and they shrink to a stutter of one sector.

Something you might take away

When several things have to change at once, the trouble is rarely the values at either end. It's the instant in between, when some parts have changed and others haven't, and anyone looking sees a state that never really existed. Gray's answer wasn't faster sensors. He chose an order where every step changes only one thing, so any reading caught mid-change is the old value or the new one. Asynchronous FIFOs pass their pointers between clock domains in Gray code for the same reason. If you can't make a change happen all at once, see whether you can break it into steps that each change one thing.