skip to content

What does an asymmetric numeral systems coder change compared with an interval-based arithmetic coder?

level: seniorimportance: nice to knowfreq 24%

answer

  1. one integer state, not two endpoints
  2. state grows by about 1/p
  3. transitions can be precomputed
  4. decoding unwinds last-in first-out
  5. speed, not better compression

basics

~20 s

It replaces the interval's two endpoints with one integer state that grows by roughly 1/p per symbol, making the hot path a table lookup rather than a multiply and divide. Decoding then runs in reverse order, so blocks are buffered.

solid answer

~50 s

Asymmetric numeral systems keep the same accounting — a symbol still costs about `log2(1/p)` — but hold it in **one** integer state `x` instead of an interval's two endpoints. Encoding a symbol maps `x` to a larger state, roughly `x/p`, placing it in the part of the number line reserved for that symbol; decoding reads the symbol out of `x` and returns the previous state. Renormalisation streams whole bytes in or out to keep `x` inside a fixed window. Because the encode step is a pure function of the state and the symbol, a table-driven variant can precompute every transition, giving symbol-code-like speed at near-interval-coder compression. Two quirks follow: the decoder unwinds the state in **last-in, first-out** order, so encoders usually process a block backwards, and probabilities are quantised to a table whose size is a power of two.

go deeper

for a junior

Recall only the headline: it is a coder that keeps a single integer state instead of an interval, and it is chosen for speed rather than for a better compression ratio.

for a middle

Explain how the state stands in for the interval — growing by roughly 1/p per symbol — and why a pure state transition can be precomputed into a table.

for a senior

Discuss the consequences that reach a design: reverse decode order forcing block buffering, quantised probabilities, and per-block rather than per-symbol adaptation.

for a principal

Decide on the axis that matters: identical compression for a given model, so the choice is throughput, buffering and how often the distribution needs to change.

## Same accounting, different state Asymmetric numeral systems are not a different theory of compression. A symbol whose probability is `p` still costs about `log2(1/p)` bits, and the quantity being accumulated is still the message's probability. What changes is the **representation of the coder's state**. An interval coder carries two numbers — the current `low` and `range` — and narrows them multiplicatively. A numeral-system coder carries **one** natural number `x`, and thinks of coding as appending information to it in a numbering system whose digits have unequal weights. Encoding symbol `s` maps `x` to a larger state of roughly `x / p(s)`, chosen so that the new state lands in the subset of the integers reserved for `s`; decoding inspects `x`, reads off which subset it is in to recover `s`, and returns the smaller state that produced it. The growth of `x` is exactly the accumulation of `log2(1/p)` bits, and renormalisation shifts whole bytes out of the bottom of `x` (or back in, when decoding) to keep it inside a fixed window. ## Why it is fast The encode transition is a pure function of `(state-within-window, symbol)`. That means it can be **precomputed into a table**, so the per-symbol hot path becomes a lookup, a shift and a compare rather than a multiplication and a division. Two further properties fall out: - **No pending-bit bookkeeping.** There is no interval to straddle a midpoint, so the deferred-bit and carry-propagation machinery of an interval coder has no counterpart. - **Interleaving.** Several independent states can be advanced over one output buffer, which suits wide execution far better than a single dependent chain of multiplies. This is the practical reason these coders displaced interval coders in throughput-sensitive pipelines: they recover most of the speed of a whole-codeword scheme while keeping fractional-bit costs. ## What it costs - **Reverse order.** The state is a stack: the last symbol encoded is the first one decoded. Encoders therefore buffer a block and encode it backwards so that the decoder emits it forwards. That makes the block, not the symbol, the natural unit and rules out an unbounded streaming encoder that never buffers. - **Quantised probabilities.** The table variant approximates each probability as a count out of a power-of-two total, so a symbol's coded cost is `log2(1/p')` for the quantised `p'`, not the exact `p`. The loss is small but real, and it grows as the table gets smaller. - **Adaptation is less natural.** An interval coder can take a fresh probability for every single symbol at no structural cost. A table-driven numeral-system coder must rebuild its table to change the distribution, so it tends to adapt **per block** rather than per symbol. Variants that compute the transition arithmetically instead of by table can adapt per symbol, at the cost of the division they were avoiding. ## The comparison | | interval coder | numeral-system coder | |---|---|---| | state | `low` plus `range` | one integer `x` | | per-symbol work | multiply, and a divide or reciprocal | table lookup, or a multiply in the arithmetic variant | | renormalisation | emit settled bits, defer midpoint straddles | shift whole bytes to keep `x` in its window | | carry handling | needed in byte-oriented forms | no interval, so no carry across emitted output | | decode order | same order as encoded | reverse of encode order, so blocks are buffered | | adapting per symbol | natural | natural only in the non-table variant | ## Where the two families end up used Because the accounting is identical, the choice is made on shape of work rather than on ratio: - A distribution that changes on **every symbol** — a context model conditioning on what it has just read — suits an interval coder, which takes a fresh probability for free. - A distribution that is **fixed for a block** and applied to millions of symbols suits a table-driven numeral-system coder, because the table is built once and amortised. - A pipeline that must **stream without buffering** suits an interval coder, since the numeral-system encoder needs the block's end before it can encode backwards. - A pipeline with **wide parallel execution** to fill suits interleaved numeral-system states, which have no shared interval to serialise on. ## When it matters in an interview This is differentiator material. The point worth making is the one that generalises: the **compression** is set by the model's probabilities, and both families spend `log2(1/p)`; the choice between them is an engineering decision about throughput, buffering and how often the distribution changes. A candidate who presents numeral-system coding as "better compression" has the wrong axis — it is, if anything, fractionally worse for the same model, and it is chosen for speed and for how well it maps onto wide, interleaved execution.

  • Why do encoders using this scheme typically process a block backwards?
    Because the single state behaves like a stack: the last symbol pushed is the first one the decoder pops. Encoding the block in reverse means the decoder unwinds it in the original order. It also fixes the block as the unit of work, since the encoder must know where the block ends before it starts.
  • Does it compress better than an interval coder given the same model?
    No — slightly worse, if anything. Both spend about `log2(1/p)` per symbol, and the table-driven variant additionally quantises each probability to a count out of a power-of-two total, which adds a small loss. It is chosen for throughput and for how well several states interleave, not for ratio.

saying these in an interview costs you the question

  • Claims it compresses better than an interval coder
  • Thinks it removes the need for a probability model
  • Expects decoding to run in the same order as encoding
  • Assumes per-symbol adaptation is free in the table variant
  • Describes the state as an interval with two endpoints