Spójrzmy na nieco inny sposób myślenia o kodowaniu Huffmana.
Załóżmy, że masz alfabet trzech symboli, A, B i C, z prawdopodobieństwem 0,5, 0,25 i 0,25. Ponieważ wszystkie prawdopodobieństwa są odwrotnymi potęgami dwóch, ma on optymalny kod Huffmana (tzn. Jest identyczny z kodowaniem arytmetycznym). W tym przykładzie użyjemy kodu kanonicznego 0, 10, 11.
Załóżmy, że naszym stanem jest duża liczba całkowita, którą nazwiemy . Możesz myśleć o kodowaniu jako o funkcji, która przyjmuje bieżący stan oraz symbol do zakodowania i zwraca nowy stan:s
kodować ( s , A )kodować (s,B)kodować (s,C)= 2 s= 4 s + 2= 4 s + 3
Zacznijmy więc od stanu 11 (który jest 1011 w systemie binarnym), kodujemy symbol B. Nowy stan to 46, czyli 101110 w trybie binarnym. Jak widać, jest to „stary” stan z sekwencją 10 dodaną na końcu. Mamy w zasadzie „wyjście” sekwencji bitów 10.
Na razie w porządku.
Zastanów się teraz, jak działa kodowanie arytmetyczne. Jeśli umieścisz prawdopodobieństwa nad wspólnym mianownikiem, symbol A faktycznie reprezentuje zakres symbol B reprezentuje zakres[2[ 04, 24)a symbol C reprezentuje zakres[3[ 24, 34).[ 34, 44)
Zasadniczo mnożymy wszystko przez wspólny mianownik. Wyobraź sobie, że stan faktycznie znajdował się w bazie 4. Kodowanie symbolu B naprawdę wypisuje cyfrę 2 z tej bazy, a kodowanie symbolu C wypisuje cyfrę 3 z tej bazy.
Jednak symbol A jest nieco inny, ponieważ nie jest to cała cyfra w bazie 4.
Zamiast tego możemy myśleć o alfabecie jako o zestawie symboli A_0, A_1, B, C, z jednakowym prawdopodobieństwem. To znowu ma optymalny kod Huffmana 00, 01, 10, 11. Lub znowu, możemy pomyśleć o tym w bazie 4. Aby zakodować symbol, po prostu:
kodować (s, A0)kodować (s, A1)kodować (s,B)kodować (s,C)= 4 s + 0= 4 s + 1= 4 s + 2= 4 s + 3
Więc teraz jest jasne, jak zakodować symbole B i C, ale aby zakodować symbol A, mamy wybór. Które z i A 1 powinniśmy użyć?A0A1
Teraz tutaj jest mądry pomysł: kradniemy jeden bit informacji ze stanu :s
i=smod2
s′=⌊s2⌋
i=smod2
a następnie .encode(s′,Ai)
Korzystając z naszego poprzedniego przykładu, , stwierdzamy, że s ′ = 5 i i = 1 , a następnie kodujemy ( 5 , A 1 ) = 4 × 5 + 1 = 21 . Nowy stan to 10101 w systemie binarnym.s=11s′=5i=1encode(5,A1)=4×5+1=21
Teraz nie daje to dokładnie takiego samego wyniku bitowego jak kodowanie Huffmana, ale generuje wyjście o tej samej długości. Mam nadzieję, że zobaczycie, że jest to również wyjątkowo dekodowalne. Aby zdekodować symbol, bierzemy resztę po podzieleniu przez 4. Jeśli wartość wynosi 2 lub 3, wówczas symbolem jest odpowiednio B lub C. Jeśli jest to 0 lub 1, to symbolem jest A, a następnie możemy cofnąć kawałek informacji, mnożąc stan przez 2 i dodając 0 lub 1.
3525
encode(s,A0)encode(s,A1)encode(s,A2)encode(s,B0)encode(s,B1)=5s+0=5s+1=5s+2=5s+3=5s+4
s′=⌊s3⌋i=smod3encode(s′,Ai)
pq
Powodem, dla którego jest to rodzina metod kodowania, jest to, że to, co tu widzieliśmy, jest samo w sobie niepraktyczne; potrzebuje pewnych modyfikacji, aby poradzić sobie z faktem, że prawdopodobnie nie masz liczb całkowitych o nieskończonej precyzji, aby skutecznie manipulować zmienną stanu, i istnieją różne sposoby, aby to osiągnąć. Kodowanie arytmetyczne ma oczywiście podobny problem z precyzją swojego stanu.
Praktyczne warianty obejmują rANS („r” oznacza „stosunek”) i tANS („sterowany tabelą”).
ANS ma kilka interesujących zalet w porównaniu z kodowaniem arytmetycznym, zarówno praktycznych, jak i teoretycznych:
- W przeciwieństwie do kodowania arytmetycznego „stan” jest pojedynczym słowem, a nie parą słów.
- Ponadto koder ANS i odpowiadający mu dekoder mają identyczne stany, a ich operacje są całkowicie symetryczne. Rodzi to kilka interesujących możliwości, takich jak możliwość przeplatania różnych strumieni zakodowanych symboli i wszystko synchronizuje się idealnie.
- Praktyczne implementacje muszą oczywiście „wysyłać” informacje na bieżąco, a nie tylko gromadzić je w dużej liczbie całkowitej, którą należy zapisać na końcu. Jednak rozmiar „wyjścia” można skonfigurować w zamian za (zwykle niewielką) utratę kompresji. Tak więc tam, gdzie kodery arytmetyczne muszą wypisywać bit po czasie, ANS może wysyłać bajt lub wątek jednocześnie. Zapewnia to bezpośredni kompromis między prędkością a kompresją.
- Wydaje się, że jest tak szybki na sprzęcie obecnej generacji, jak binarne kodowanie arytmetyczne, a zatem jest konkurencyjny w stosunku do kodowania Huffmana. To sprawia, że jest on znacznie szybszy niż kodowanie arytmetyczne dużymi alfabetami i jego warianty (np. Kodowanie zakresu).
- Wydaje się być wolny od patentów.
Nie sądzę, żebym kiedykolwiek ponownie używał kodowania arytmetycznego.