Główną ideą kompresji arytmetycznej jest możliwość kodowania prawdopodobieństwa przy użyciu dokładnej ilości wymaganej długości danych.
Ta ilość danych jest znany, świadczy Shannon i mogą być obliczane tylko przy użyciu następującego wzoru: -log2 (p)
Przykładowo, gdy p = 50%, to konieczne 1 bit. A jeśli p = 25%, potrzebujesz 2 bitów.
Jest to dość proste dla prawdopodobieństw o sile 2 (w tym szczególnym przypadku kodowanie Huffmana może wystarczyć). Ale co, jeśli prawdopodobieństwo wynosi 63%? Następnie potrzebujesz -log2 (0.63) = 0.67 bitów. Brzmi trudno ...
Ta właściwość jest szczególnie ważna, jeśli prawdopodobieństwo jest wysokie. Jeśli potrafisz przewidzieć coś z 95% dokładnością, potrzebujesz tylko 0,074 bitów, aby przedstawić dobre domysły. Co oznacza, że będziesz dużo kompresować.
Teraz, jak to zrobić?
Cóż, to jest prostsze niż się wydaje. Będziesz dzielił swój zakres w zależności od prawdopodobieństw. Na przykład, jeśli masz zakres 100, 2 możliwe zdarzenia i prawdopodobieństwo 95% dla pierwszego, to pierwsze 95 wartości powie "Zdarzenie 1", a ostatnie 5 pozostałych wartości powie "Zdarzenie 2" .
OK, ale na komputerach jesteśmy przyzwyczajeni do używania mocy 2. Na przykład, z 16 bitami, masz zakres 65536 możliwych wartości. Zrób to samo: weź 1. 95% zakresu (czyli 62259), aby powiedzieć "Wydarzenie 1", a pozostałe powiedz "Wydarzenie 2". Najwyraźniej masz problem "zaokrąglania" (precyzji), ale dopóki masz wystarczająco dużo wartości do dystrybucji, nie ma to większego znaczenia. Co więcej, nie jesteś ograniczony do 2 wydarzeń, możesz mieć niezliczoną liczbę zdarzeń. Liczy się tylko to, że wartości są przydzielane w zależności od prawdopodobieństw każdego zdarzenia.
OK, ale teraz mam 62259 możliwych wartości do powiedzenia "Zdarzenie 1" i 3277 do powiedzenia "Zdarzenie 2". Który powinienem wybrać ? Cóż, każdy z nich to zrobi. Wether to 1, 30, 5500 lub 62256, nadal oznacza "Event 1".
W rzeczywistości decydowanie, która wartość wybrać nie będzie zależało od bieżącego odgadnięcia, ale od następnych.
Załóżmy, że mam "Zdarzenie 1". Teraz muszę wybrać dowolną wartość z przedziału od 0 do 62256. Przy następnym założeniu mam taką samą dystrybucję (95% Zdarzenie 1, 5% Zdarzenie 2). Po prostu przydzielę mapę dystrybucji z tymi prawdopodobieństwami. Tyle, że tym razem jest on rozprowadzany po 62256 wartościach. I kontynuujemy tak, zmniejszając zakres wartości za każdym razem.
Tak więc definiujemy "zakresy", które ograniczają się do każdego odgadnięcia. W pewnym momencie istnieje jednak problem dokładności, ponieważ pozostają bardzo małe wartości.
Ideą jest po prostu "nadmuchanie" zakresu ponownie. Na przykład, za każdym razem, gdy zakres spada poniżej 32768 (2^15), wysyłasz najwyższy bit i mnożymy resztę przez 2 (skutecznie przesuwając wartości o jeden bit w lewo). Przez ciągłe robienie tego w ten sposób, wyprowadzasz bity jeden po drugim, ponieważ są one ustalane według serii domysłów.
Teraz relacja z kompresją staje się oczywista: gdy zakres jest zawężany szybko (np. 5%), wyprowadzasz wiele bitów, aby uzyskać zasięg powyżej limitu. Z drugiej strony, gdy prawdopodobieństwo jest bardzo wysokie, zakres zawęża się bardzo powoli. Przed wydrukowaniem pierwszych bitów możesz mieć wiele domysłów. W ten sposób można skompresować zdarzenie do "ułamka sekundy".
Celowo użyłem terminów "prawdopodobieństwo", "domysły", "zdarzenia", aby zachować ogólny charakter tego artykułu. Ale w przypadku kompresji danych wystarczy je zastąpić sposobem, w jaki modelujesz dane. Na przykład następnym zdarzeniem może być następny bajt; w tym przypadku masz ich 256.
Teraz rozumiem pytanie. –
Możesz znaleźć bardzo szczegółowe wyjaśnienie kodowania arytmetycznego, a także algorytmów [w tym artykule Arturo San Emeterio Campos] (http://www.arturocampos.com/ac_arithmetic.html). Również możesz zobaczyć implementację C++ dla tych algorytmów w [tym poście] (http://stackoverflow.com/a/10017164/1009831). –