background image

 

 

YaQzi

Kodowanie arytmetyczne

TiK? TAK! TiK? TAK!

TiK? TAK! … TiK-TAK!

background image

 

 

YaQzi

Kodowanie

Do zakodowania wiadomości tym sposobem potrzebny nam 

będzie zestaw znaków, których użyjemy w wiadomości oraz częstość 
występowania każdego z tych znaków. Musimy znaleźć taki podprzedział 
przedziału (0;1), który jednoznacznie określi ciąg znaków wyznaczany 
rekursywnie na podstawie prawdopodobieństwa ich wystąpienia. Brzmi 
skomplikowanie ale robi się to prosto. 

Dla przykładu załóżmy sobie takie dane:

Znak

Częstość występowania

A

0.5

B

0.3

C

0.2

chcemy zakodować ciąg „BACA”

background image

 

 

YaQzi

Znak

Częstość występowania

A

0.5

B

0.3

C

0.2

0

0.5

0.8

1

Bierzemy przedział (0;1) i dzielimy go na części, z których każda będzie 
odpowiadać danemu znakowi. Szerokość podprzedziałów musi być 
proporcjonalna do częstości wystąpienia danego znaku. Mamy więc coś 
takiego:

0.5

0.3

0.2

A

B

C

background image

 

 

YaQzi

Znak

Częstość występowania

A

0.5

B

0.3

C

0.2

0

0.5

0.8

1

B

ACA

A

B

C

Jako pierwszy kodujemy znak „B”. Odpowiada mu przedział (0.5;0.8). 

Zaznaczamy go i dzielimy na nowe podprzedziały 

proporcjonalne

 do tych 

pierwszych.

0.5

0.65

0.74

0.8

background image

 

 

YaQzi

Znak

Częstość występowania

A

0.5

B

0.3

C

0.2

B

A

CA

Drugi znak to „A”. Wybieramy podprzedział z otrzymanego przed chwilą 
przedziału, odpowiadający znakowi A, a więc (0.5;0.65). Zaznaczamy go i 
dzielimy na proporcjonalne podprzedziały.

0.5

0.65

0.74

0.8

A

B

C

0.5

0.575

0.62

0.65

background image

 

 

YaQzi

Znak

Częstość występowania

A

0.5

B

0.3

C

0.2

BA

C

A

Analogicznie postępujemy ze znakiem C…

0.5

0.575

0.62

0.65

A

B

C

0.62

0.635

0.644

0.65

background image

 

 

YaQzi

Znak

Częstość występowania

A

0.5

B

0.3

C

0.2

BAC

A

Ostatni znak to „A”. Odpowiada mu podprzedział (0.62;0.635) i to właśnie 
ten podprzedział trzeba zakodować binarnie, ale żeby nie było za łatwo 
trzeba go zakodować jednoznacznie, tzn. z odpowiednią ilością zer na 
końcu. 

A

B

C

0.62

0.635

0.644

0.65

background image

 

 

YaQzi

0.620  …  0.635

Jak wiadomo nie wszystkie liczby 

zmiennoprzecinkowe można zapisać w postaci binarnej. 
Wystarczy jednak, że znajdziemy dowolną, która zmieści 
się w tym przedziale. No i najlepiej, żeby była ona jak 
najkrótsza. Żeby było lepiej widać o co chodzi wklejam 
tablicę z wartościami poszczególnych bitów rozwinięcia 
dziesiętnego.

1

0,50000000

2

0,25000000

3

0,12500000

4

0,06250000

5

0,03125000

6

0,01562500

7

0,00781250

8

0,00390625

9

0,00195313

10

0,00097656

11

0,00048828

12

0,00024414

13

0,00012207

14

0,00006104

15

0,00003052

16

0,00001526

17

0,00000763

18

0,00000381

19

0,00000191

20

0,00000095

Widać, że suma bitów 1 i 3 jest cacy:

0,101

2

 = 0.5 + 0.125 = 0.625

„0,” występuje w każdej liczbie z przedziału (0;1) więc w 

kodzie arytmetycznym jest to pomijane. Mamy więc 

wstępną formę zakodowanego ciągu „BACA”:

101

background image

 

 

YaQzi

0.62  …  0.635

1

0,50000000

2

0,25000000

3

0,12500000

4

0,06250000

5

0,03125000

6

0,01562500

7

0,00781250

8

0,00390625

9

0,00195313

10

0,00097656

11

0,00048828

12

0,00024414

13

0,00012207

14

0,00006104

15

0,00003052

16

0,00001526

17

0,00000763

18

0,00000381

19

0,00000191

20

0,00000095

101

Teraz musimy sprawdzić, czy jeśli za przesłaniem kodu 
wystąpią jakieś domyślne dla kanału jedynki – liczba 
wyskoczy z potrzebnego nam przedziału. Jeśli tak – 
musimy na końcu kodu dopisać 0 i sprawdzić wariant z 
jedynkami ponownie – dopóki dopisanie jedynek niczego 
nie zmieni. No więc…

Teraz mamy: 0,101 -> 0.625

Po dopisaniu: 0,10111111111… -> ???

Ale skąd wiadomo ile to jest 0,0001111111… ? Nie 
zagłębiając się w szczegóły – patrzymy na którym bicie 
jest ostatnie zero po przecinku. W tym wypadku jest na 
trzecim miejscu. Patrzymy w tabelce jaka jest wartość 3 
bitu -> 0,125. Suma wszystkich jedynek za trzecim 
bitem, a więc wartość 0,0001111111… jest równa 

prawie

 0,125, a więc 0,12499999999… Taka fajna 

własność każdemu systemu. Kto nie wierzy niech sobie 
policzy. ;)

background image

 

 

YaQzi

0.62  …  0.635

1

0,50000000

2

0,25000000

3

0,12500000

4

0,06250000

5

0,03125000

6

0,01562500

7

0,00781250

8

0,00390625

9

0,00195313

10

0,00097656

11

0,00048828

12

0,00024414

13

0,00012207

14

0,00006104

15

0,00003052

16

0,00001526

17

0,00000763

18

0,00000381

19

0,00000191

20

0,00000095

101

No to sprawdzamy:

Teraz mamy: 0,101 -> 0.625

Po dopisaniu: 0,10111111111… -> 0.625 + 0.124(9) = 
0.76(9)

Górne ograniczenie przedziału to 0.635 więc jedynki 
przeskoczyły przedział – trzeba dopisać 0

background image

 

 

YaQzi

0.62  …  0.635

1

0,50000000

2

0,25000000

3

0,12500000

4

0,06250000

5

0,03125000

6

0,01562500

7

0,00781250

8

0,00390625

9

0,00195313

10

0,00097656

11

0,00048828

12

0,00024414

13

0,00012207

14

0,00006104

15

0,00003052

16

0,00001526

17

0,00000763

18

0,00000381

19

0,00000191

20

0,00000095

1010

Sprawdzamy znowu:

Teraz mamy: 0,1010 -> 0.625

Po dopisaniu: 0,10101111111… -> 0.625 + 0.0624(9) = 
0.6874(9)

Znowu pojechało za przedział. Dopisujemy kolejne 0.

background image

 

 

YaQzi

0.62  …  0.635

1

0,50000000

2

0,25000000

3

0,12500000

4

0,06250000

5

0,03125000

6

0,01562500

7

0,00781250

8

0,00390625

9

0,00195313

10

0,00097656

11

0,00048828

12

0,00024414

13

0,00012207

14

0,00006104

15

0,00003052

16

0,00001526

17

0,00000763

18

0,00000381

19

0,00000191

20

0,00000095

10100

Sprawdzamy znowu:

Teraz mamy: 0,10100 -> 0.625

Po dopisaniu: 0,10100111111… 

-> 0.625 + 0.03124(9) = 

0.65624(9)

Znowu za dużo. Dopisujemy kolejne 0.

101000

Sprawdzamy znowu:

Teraz mamy: 0,101000 -> 0.625
Po dopisaniu: 0,10100011111… 

-> 

0.625 + 0.015624(9) = 

0.640624(9)

Nadal dupa… czyli kolejne zero na koniec.

background image

 

 

YaQzi

0.62  …  0.635

1

0,50000000

2

0,25000000

3

0,12500000

4

0,06250000

5

0,03125000

6

0,01562500

7

0,00781250

8

0,00390625

9

0,00195313

10

0,00097656

11

0,00048828

12

0,00024414

13

0,00012207

14

0,00006104

15

0,00003052

16

0,00001526

17

0,00000763

18

0,00000381

19

0,00000191

20

0,00000095

1010000

Sprawdzamy znowu:

Teraz mamy: 0,1010000 -> 0.625
Po dopisaniu: 

0,10100001111… -> 0.625 + 0.0078124(9) = 

0.6328124(9)

Tym razem górny przedział nie zostanie przekroczony. 
Mamy więc zakodowany ciąg „BACA”:

1010000

Użyliśmy 7 bitów do zakodowania 4 znaków.

Średnia wyszła więc 1,75 bitu na słowo.

background image

 

 

YaQzi

Jeśli ktoś chce poćwiczyć sobie kodowanie na innym zestawie znaków i 
prawdopodobieństwach, może skorzystać do sprawdzenia wyniku z 
programu:

Nie zabezpieczałem go przed niepoprawnymi wartościami więc bardzo 
łatwo go wyłożyć, ale dla poprawnych wartości i odpowiednio krótkich 
ciągów działa. Trzeba pamiętać, że suma prawdopodobieństw musi być 
równa 1.

Przykład z prezentacji:

program

background image

 

 

YaQzi

Dekodowanie

1

0,50000000

2

0,25000000

3

0,12500000

4

0,06250000

5

0,03125000

6

0,01562500

7

0,00781250

8

0,00390625

9

0,00195313

10

0,00097656

11

0,00048828

12

0,00024414

13

0,00012207

14

0,00006104

15

0,00003052

16

0,00001526

17

0,00000763

18

0,00000381

19

0,00000191

20

0,00000095

1010000

Zamieniamy 0,101 na wartość dziesiętną: 0,625, 
rozpisujemy sobie przedziały i patrzymy, do którego 
podprzedziału ona trafi. Wybrany podprzedział dzielimy 
ponownie na podprzedziały, szukamy, w którym jest 
0,625 itd…

A

B

C

0

0.5

0.8

1

A

B

C

0.5

0.65

0.74

0.8

A

B

C

0.5

0.575

0.62

0.65

A

B

C

  0.62

0.635

0.644

0.65

background image

 

 

YaQzi

Uwaga końcowa

Skąd wiadomo kiedy zatrzymać się w tym odczytywaniu? Przecież po 
odczytaniu BACA można dalej podzielić sobie to ostatnie A i czytać 
kolejne znaki. Ano można i nie wiadomo kiedy się zatrzymać. Problem 
ten rozwiązuje się na dwa sposoby:

- podaje się po prostu ile znaków należy odczytać,
- do zestawu znaków dodaje się ‘znak końca’ - # albo inny szlaczek. 

Wtedy przy kodowaniu po ostatniej literze ‘trafiamy’ właśnie w tą # i 
kodujemy jej przedział a przy odczytywaniu po prostu czytamy do 
momentu trafienia na #. Tyle…


Document Outline