Codificação run-length (RLE)

Digite qualquer texto e observe-o se dividir em sequências — repetições consecutivas do mesmo caractere colapsam em um único par (símbolo, contagem). Sequências longas reduzem os dados; sequências curtas os fazem crescer.

A carregar a simulação interativa...

Lição

A teoria — Codificação run-length (RLE)

A codificação por comprimento de sequências substitui cada sequência maximal de símbolos iguais por um único par (símbolo, contagem). À leitura não chega o texto, mas dois números: N caracteres e R sequências. Todos os outros valores da página são o quociente desses dois.

O que significa cada símbolo

N
o número de caracteres à entrada — o comprimento do que escreveste, nada mais.
R
o número de sequências, isto é, blocos maximais de um mesmo símbolo repetido. R sobe uma unidade onde dois vizinhos diferem: conta fronteiras, não caracteres.
N/R, o comprimento médio das sequências. É a única grandeza que decide o resultado.
ratio
N/2R, ou seja L̄/2. Acima de 1 a saída é menor do que a entrada.

De onde vem a fórmula

  1. Conta sequências, não caracteres. Em 0010111100001111 os vizinhos diferem em cinco pontos, portanto há seis sequências e a linha mostra R=6.
  2. O tamanho codificado é 2R e mais nada. Aquilo de que as sequências são feitas nunca entra na conta — seis sequências custam doze unidades, sejam píxeis, letras ou algarismos.
  3. Divide: ratio = N/2R = L̄/2. O equilíbrio fica assim em L̄ = 2, e é exatamente atingível — escreve AABB e as barras marcam 4 bytes à entrada e 4 à saída.
  4. Os dois sentidos não são simétricos. Para cima não há limite: uma única sequência de um milhão de caracteres codifica-se num par. Para baixo o piso está em 0.50× e não pode ser batido, porque o pior que uma entrada consegue fazer é dar a cada caractere a sua própria sequência.

Como ler o que vê

Os quatro exemplos têm exatamente dezasseis caracteres, o que compensa lê-los como conjunto. Linha de imagem tem três sequências e dá 6 bytes. Sequências clássicas tem quatro e dá 8. Máscara de bits tem seis e dá 12. Pior caso tem dezasseis e dá 32. O mesmo comprimento à entrada e sai entre 6 e 32 bytes — um fator de cinco, decidido inteiramente por R. Escreve depois hello world: onze caracteres, dez sequências, 20 bytes. A prosa comum fica na parte baixa desse intervalo, e é essa toda a razão por que este método é uma peça dentro de compressores e não um compressor por si.

Pressupõe
Que um par custa exatamente 2 unidades, que um símbolo e uma contagem ocupam o mesmo, e que uma contagem pode ter qualquer tamanho. Os codificadores reais dão à contagem uma largura fixa — um byte, ou seja 255 — e têm de partir uma sequência mais longa em vários pares, o que empurra o equilíbrio um pouco acima de 2. O pressuposto de largura igual falha precisamente onde este método é melhor: num fax de 1 bit o símbolo ocupa um bit e a contagem não.
Falha quando
O piso de 0.50× não é um defeito à espera de solução. Um codificador sem perdas tem de ser reversível, de modo que entradas distintas deem saídas distintas; e há menos cadeias curtas do que longas para onde as enviar. Qualquer esquema que encurte sequer uma entrada alonga forçosamente outra. É um facto de contagem, não uma propriedade deste método. O PackBits, na terceira ideia acima, baixa o seu pior caso para um byte de controlo por cada 128 — menos de 1% — e mais longe ninguém vai, porque o piso pode descer sem limite mas nunca ser alcançado. O que este método faz é carregar esse custo por fora, numa leitura que se vê mexer.

por que o ponto de equilíbrio é exatamente 2 🖖

Cada sequência — não importa o quão longa — custa o mesmo para armazenar: 2 unidades, uma para o símbolo, uma para a contagem. Uma sequência de comprimento L só vale a pena codificar quando isso custa menos do que escrever L caracteres brutos — ou seja, quando L é maior que 2. Em média, sobre toda a entrada, essa condição se torna L̄ = N/R maior que 2, onde N é o comprimento total e R é o número de sequências — exatamente a linha que a fórmula acima verifica. Essa é também a razão pela qual o RLE é um compressor de propósito geral fraco: texto em inglês, código-fonte e dados aleatórios raramente têm sequências mais longas que 2, por isso o RLE fica reservado a dados projetados de propósito para ter sequências longas — digitalizações de fax de 1 bit, bitmaps esparsos e imagens com paleta e áreas de cor sólida. Formatos reais levam essa ideia mais longe: o PNG aplica um filtro delta Paeth/Sub/Up em cada linha de varredura antes de comprimir, transformando primeiro gradientes suaves em longas sequências de diferenças quase nulas — o RLE (via DEFLATE) faz o resto. Experimente o exemplo de pior caso acima: dezesseis caracteres distintos geram dezesseis sequências de comprimento 1, então a codificação precisa de 32 unidades para armazenar 16 — a entrada dobra de tamanho.

a compressão que você inventaria sozinho 🖖

A codificação por comprimento de série é a única ideia de compressão que você poderia reinventar por conta própria: em vez de escrever WWWWWWW letra por letra, você diz apenas "7 W" — o mesmo atalho que usamos ao ler "três vezes sete" em um número de telefone. Ela percorre os dados numa única passagem da esquerda para a direita e não guarda nada além da série que está contando, o que a torna rápida e fácil de transmitir em fluxo. E é sem perdas: a partir dos pares (símbolo, contagem) você reconstrói o original exatamente, ao contrário de JPEG ou MP3, que descartam detalhe para sempre.

o primo do RLE que não pode estourar 🖖

O RLE ingênuo pode dobrar dados incompressíveis, mas a variante PackBits da Apple — nascida no MacPaint dos anos 1980 e ainda um modo de compressão padrão no TIFF — é projetada para quase nunca crescer. Cada bloco começa com um byte de controle com sinal: um valor não negativo significa "os próximos bytes são literais", um negativo "repita o byte seguinte". Dados únicos são copiados sem alteração em blocos de até 128 bytes, então o pior caso acrescenta apenas um byte de controle por 128 — menos de 1% de sobrecarga em vez dos 100% que o RLE ingênuo pode atingir.

Problema resolvido na íntegra

  1. Codificação run-length de AAAAAABBBCCDDDDD em quatro pares 5 passos

    A codificação por comprimento de corrida transforma AAAAAABBBCCDDDDD em quatro pares. Calcule a compressão e, em seguida, a condição exata sob a qual este esquema torna um ficheiro maior.

    1. A codificação é a mais óbvia: substituir cada sequência pelo caráter e pelo seu comprimento. Dezasseis carateres reduzem-se a quatro pares.

    2. Dois números descrevem qualquer entrada deste esquema — o seu comprimento e o seu número de sequências — e a sua razão é o comprimento médio das sequências. Aqui é 4.

    3. Agora conte honestamente. Cada par custa dois símbolos, um caráter e uma contagem, pelo que a saída é 2R contra uma entrada de N. Mais nada sobre os dados importa.

    4. Assim, o esquema ganha exatamente quando 2R < N, o que se rearranja num comprimento médio de sequência superior a 2. Aqui são 8 contra 16 — uma redução exata para metade — e a linha de veredito no painel diz a mesma coisa num único símbolo.

    5. Abaixo desse limiar perde, e com um comprimento médio de sequência de 1 perde ao máximo: cada caráter torna-se um par, duplicando o ficheiro.

    Resposta

    A ferramenta apresenta N = 16 e R = 4, uma sequência média de 4 e uma poupança de 2×. A condição é o aspeto a reter: o RLE comprime se e só se as sequências tiverem em média mais de dois elementos, e é um dos poucos esquemas de compressão cujo ponto de equilíbrio é um único número que pode verificar a olho nu. Digite ABCD na caixa e veja-o expandir para o dobro do tamanho. Isso não é uma falha — é a razão pela qual o RLE sobrevive apenas onde as sequências são garantidas por construção: linhas de varrimento de fax, mapas de bits esparsos e as regiões uniformes de um JPEG após a quantização, nunca em texto geral.

Percurso de aprendizagem

Compressão manual

Conduz a Huffman a ideia na sua forma mais simples: substituir uma sequência de símbolos idênticos pelo símbolo e uma contagem.

Referências (3)

Problemas de exemplo

  • Sequências clássicas - "AAAAAABBBCCDDDDD" → (A,6)(B,3)(C,2)(D,5) — 16 caracteres em 8 pares
  • Pior caso - "ABCDEFGHIJKLMNOP" — todos os caracteres únicos, cada par fica mais longo que o original
  • Máscara de bitmap - "0010111100001111" — linha de pixels que mostra por que o PNG faz pré-filtragem antes do RLE
  • Linha de varredura de imagem - "WWWWWWWBBBBBWWWW" — linha simples de imagem em preto e branco, com forte estrutura de sequências