Bignum Factorial

Big Numbers

n! computed live on a Super Nintendo using schoolbook carry-propagation multiply across a 700-element base-10000 bignum array. Each step multiplies every cell by n, propagates the carry, and renders the growing decimal number — up to 2800 digits — filling 27 rows of BG3 tilemap. Runs automatically; no joypad needed. Written in C and compiled with the llvm-mos-based 65816 toolchain (+mos-a16, 16-bit accumulator mode).

loading core…

Self-running demo — the factorial number grows automatically.

Click the screen to focus, then watch. Tab away and it pauses.

What it is

The demo computes n! incrementally: at each step it multiplies the bignum by n using the schoolbook carry-propagation algorithm, then re-renders the full decimal expansion on screen. The number is stored in a 700-element little-endian base-10000 array — each uint16 cell holds 4 decimal digits:

for i in 0..nelem:
    prod    = d[i] × n + carry   // __mulsi3 (u16×u16→u32)
    d[i]    = prod mod 10000     //
    carry   = prod div 10000     // __udivmodsi4 (both quot+rem in same expr)
while carry:
    d[nelem++] = carry mod 10000
    carry      = carry div 10000

1000! has 2568 decimal digits — 642 base-10000 elements — and fills roughly 27 rows of the 256×224 SNES screen. The HUD row at the bottom shows the current n and digit count.

Compiler stress-test

ItemWhat it exercises
AlgorithmSchoolbook carry-propagation multiply across a 700-element uint16 array in base 10000 — one multiply + combined divide+mod per element per factorial step
RepresentationLittle-endian base-10000 bignum: each uint16 cell holds 4 decimal digits 0–9999; 700 cells cover up to 2800 decimal digits (1000! ≈ 2568 digits)
__mulsi332×32→32 multiply called once per inner-loop iteration (d[i] × n); emitted because both operands widen to uint32
__udivmodsi4Combined 32÷32 divide+mod; clang emits this single libcall (not separate udivsi3/umodsi3) when both quotient and remainder of the same division are live in the same expression
rep/sepMode-switch brackets mark 16-bit accumulator sections under +mos-a16; 14 occurrences in the inner loop

The algorithm is a portable C header (examples/65816/factorial.h) linked into the SNES ROM and separately into a host oracle. The gate asserts corpus_result — a 16-bit rotate-XOR CRC of the 50! digit array — is identical on host, default 8-bit SNES, +mos-a16, and +mos-xy16: a five-way differential.

Written in C with the llvm-mos 65816 toolchain and verified against two emulators (MAME + bsnes-jg). Hit Verify fidelity to reproduce the build gate's WRAM assert (gate CRC 0x772F, 50!) live in this tab. No far pointers — the same binary passes five ways: host == default == +mos-a16 == +mos-xy16 == bsnes-jg.