Domain Colouring
Fractals Domain colouring turns a complex
function into a picture. This one is a rational map, (z²−1)/(z²+c), and where its
denominator hits zero it has poles — the divide there yields infinity or
NaN, which the code catches with the test
x != x to paint the singularities. Software floating point on a chip with no FPU;
the picture develops one row at a time, then shimmers. Runs on its own; no joypad needed. Written
in C and compiled with the llvm-mos-based 65816
toolchain (+mos-a16, 16-bit accumulator mode).
Self-running demo — the field develops a row at a time, then the palette shimmers.
Click the screen to focus, then watch. Tab away and it pauses.
What it is
A pole of a function is a point where it blows up to infinity. Numerically, that's a divide by zero — and the result is either infinity or, if the numerator is zero too, "not a number":
f(z) = (z*z - 1) / (z*z + c); // complex rational map // at a pole z*z + c == 0, so we divide by zero: inv = 1.0f / 0.0f; // = +Inf fr = numerator * inv; // Inf, or 0*Inf = NaN if (fr != fr) colour = POLE; // isnan: only NaN != itself
NaN has a strange property: it is not equal to anything, including itself. So x != x
is the standard test for it, and it compiles to an unordered comparison — a different
machine operation than the ordered less-than every other float demo used. The picture stays
bit-exact across every codegen mode.
Compiler stress-test
| Item | What it exercises |
|---|---|
| NaN / unordered compares | A pole is where the function divides by zero, producing infinity or NaN. Detecting NaN is the test x != x — true only for NaN — which the compiler lowers to an "unordered" floating-point comparison. Every earlier float demo used only ordered less-than; this is a different set of comparison routines. |
| fold the outcome, not the bits | A NaN's exact bit pattern is not fully pinned down by the standard, so the self-check never hashes raw float bits — it hashes the colour chosen (pole or not), which is a yes/no answer identical on the host and the console. That keeps the test about the comparison, not the payload. |
| soft float, one op per line | The 65816 has no floating-point unit, so every add, multiply and reciprocal is a library call — and each is written on its own line so the compiler can't fuse a multiply-add, keeping the result bit-identical to the host. |
| slow on purpose | Software floating point is heavy here (~150k cycles per cell), so the picture is a coarse 8x8 grid painted one row at a time, live on the console — proving the soft-float actually runs on hardware — then the palette cycles for a shimmer. |
Written in C with the llvm-mos 65816 toolchain and verified against bsnes-jg
(and MAME where the SPC700 IPL is present). Hit Verify fidelity to reproduce the build
gate's WRAM assert (gate CRC 0xF3FD — a fold of pole/no-pole colour outcomes,
including a guaranteed NaN pole) live in this tab. No far pointers — the same source passes every
way: host == default == +mos-a16 == +mos-xy16 == bsnes-jg,
-verify clean.