void update(int symbol) throws IOException {
        long range = high - low + 1;

        // State check
        Preconditions.checkState(low < high && (low & MASK) == low && (high & MASK) == high, "Low or high out of range");
        Preconditions.checkState(range >= MIN_RANGE && range <= MAX_RANGE, "Range out of range");

        long total = freq.total();
        long symbolLow = freq.low(symbol);
        long symbolHigh = freq.high(symbol);
        Preconditions.checkState(symbolLow != symbolHigh, "Symbol has zero frequency");
        Preconditions.checkState(total < MAX_TOTAL, "Cannot code symbol because total is too large");

        // Update range
        long newLow = low + symbolLow * range / total;
        long newHigh = low + symbolHigh * range / total - 1;
        low = newLow;
        high = newHigh;

        // While the highest bits are equal
        while (((low ^ high) & TOP_MASK) == 0) {
            shift();
            low = (low << 1) & MASK;
            high = ((high << 1) & MASK) | 1;
        }

        // While the second highest bit of low is 1 and the second highest bit of high is 0
        while ((low & ~high & SECOND_MASK) != 0) {
            underflow();
            low = (low << 1) & (MASK >>> 1);
            high = ((high << 1) & (MASK >>> 1)) | TOP_MASK | 1;
        }
    }
Arithmetic coding.

<p> This code is based on <a href="https://github.com/nayuki/Arithmetic-Coding">Nayuki's
great code</a> .
indexr-segment/src/main/java/io/indexr/compress/ArthmeticCoder.java