
In the usual (real) number line, two numbers are “close” if their leading digits agree:
is closer to
than to
.
The p-adic world flips that intuition: closeness is governed by agreement of the
low-order digits (divisibility by powers of a prime).
This post introduces a small Pygame visualization (shown as circles inside circles inside circles)
for the 3-adic integers .
The picture is inspired by the beautiful illustrations of Heiko Knospe,
and the app is meant to make two ideas feel tangible:
(1) what it means for numbers to be p-adically close, and
(2) how addition behaves in this nested, ultrametric geometry.
Hensel’s “invention” of the p-adic numbers
The p-adic numbers were first systematically introduced by Kurt Hensel (1861–1941),
a German mathematician who studied in Berlin and Bonn and was strongly influenced by
Leopold Kronecker; from 1901 onward he was a professor in Marburg.
Around 1897, Hensel realized that one can build a number system by completing the rationals
not with the usual absolute value, but with a new absolute value that measures
divisibility by a fixed prime
.
A compact way to say “p-adic closeness” is: two integers and
are close in the
p-adic sense if
is divisible by a large power of
.
Write
for the exponent of
in
.
Then
is small exactly when
is large.
If you’d like a classic reference from Hensel himself, see his book Zahlentheorie (1913), where p-adic methods appear in a mature, systematic form.
From congruences to nested circles
The 3-adic integers can be viewed as an infinite limit of congruence systems,
and that viewpoint is perfect for visualization. A basic “clopen” (closed-and-open) 3-adic ball has the form
, which you can read as “all 3-adic integers that are congruent to
modulo
.”
In the app, those balls become nested circles:
- The big circle is the whole space (schematically).
-
Inside it are 3 circles: the residue classes mod 3 (the least significant ternary digit
).
-
Inside each of those are 3 circles: refining to mod 9 (digit
).
-
Inside each of those are 3 circles: refining to mod 27 (digit
).
-
And one more layer gives mod 81 (digit
), for a total of
innermost circles labeled 0–80.
Two numbers land in the same small circle precisely when they agree modulo a high power of 3.
That’s the visual meaning of “3-adically close”: sharing deeper circles means sharing more low-order ternary digits,
i.e., for larger and larger
.
Addition as a ternary wheel
The app animates the operation (wrapping
),
and highlights (i) the active innermost circle and (ii) every circle that contains it.
Conceptually, this is the “wheel” behavior of ternary digits:
the last digit ticks 0→1→2→0, and whenever it rolls over, a carry moves to the next digit.
The nesting makes carries feel geometric. When a carry happens, the highlight doesn’t merely move to a nearby leaf; it “jumps” to a different region determined by the next digit layer. In p-adic terms, carries change higher digits, while leaving lower congruence information intact.
Here is a simple invariant you can read directly from the circles:
adding 3 does not change the residue mod 3, because .
In the visualization, that means
and
stay inside the same one of the three outer circles.
Likewise, adding 9 does not change the residue mod 9, because .
So
and
keep the same position in the second layer (the mod 9 refinement),
even though they may move around in deeper layers.
Why this picture is helpful (and what it is not)
This is not an isometric embedding of into the Euclidean plane.
It is a schematic drawing that encodes the key ultrametric fact:
balls are nested, and each ball splits cleanly into three disjoint sub-balls at the next scale.
If you want to generalize, the same idea works for any prime :
each ball splits into
sub-balls, and p-adic closeness is agreement modulo
.
The circles then become a compact way to “see” both topology (nested clopen sets) and arithmetic (addition with carries).
Credits & references
- Visualization idea inspired by the illustrations of Heiko Knospe.
- K. Hensel, Zahlentheorie, 1913.
- P-adic number wheel animation: <a href=”https://trinket.io/library/trinkets/71ecc4abf5fa” Link to Interactive Python Code
