Арифметическое кодирование — различия между версиями
| Migan (обсуждение | вклад) м (Оформление англоязычного термина) | Migan (обсуждение | вклад)  м (Добавление комментариев к коду, выделение ключевых слов) | ||
| Строка 11: | Строка 11: | ||
| # Выберем любое число из получившегося отрезка. Это и будет результат арифметического кодирования. | # Выберем любое число из получившегося отрезка. Это и будет результат арифметического кодирования. | ||
| − |   left = 0 | + |   left = 0 <span style="color:green"> // Левая граница [left; right) отрезка изначально равна 0 </span> | 
| − |   right = 1 | + |   right = 1 <span style="color:green"> // Правая граница [left; right) отрезка изначально равна 1 </span> | 
| − |   while !eof | + |   '''while''' !eof | 
| − |       read(symb) | + |       '''read'''(symb) | 
| − |       newRight = left + (right - left) * segment[symb].right <span style="color:green"> //segment[symb] — подотрезок отрезка [0; 1), | + |       newRight = left + (right - left) * segment[symb].right <span style="color:green"> // segment[symb] — подотрезок отрезка [0; 1), соответствующий символу symb  </span> | 
| − | |||
|       newLeft = left + (right - left) * segment[symb].left |       newLeft = left + (right - left) * segment[symb].left | ||
|       left = newLeft |       left = newLeft | ||
|       right = newRight |       right = newRight | ||
| − |   ans = (left + right) / 2 | + |   ans = (left + right) / 2 <span style="color:green"> // В качестве результата взята средняя точка отрезка [left; right) </span> | 
| === Декодирование === | === Декодирование === | ||
Версия 19:47, 16 июня 2016
Арифметическое кодирование (англ. Arithmetic coding) — алгоритм сжатия информации без потерь, который при кодировании ставит в соответствие тексту вещественное число из отрезка . Данный метод (как и алгоритм Хаффмана) является энтропийным т.е. длина кода конкретного символа зависит от частоты встречаемости этого символа в тексте. Арифметическое кодирование показывает более высокие результаты сжатия, чем алгоритм Хаффмана, для данных с неравномерными распределениями вероятностей кодируемых символов. Кроме того, при арифметическом кодировании каждый символ кодируется нецелым числом бит, что эффективнее кода Хаффмана (теоретически символу с вероятностью появления допустимо ставить в соответствие код длины , следовательно при кодировании Хаффманом это достигается только с вероятностями, равными обратным степеням двойки).
Содержание
Принцип действия
Кодирование
Алгоритму передаются текст для кодирования и список частот встречаемости символов.
- Рассмотрим отрезок на координатной прямой.
- Поставим каждому символу текста в соответствие отрезок, длина которого равна частоте его появления.
- Считаем символ из входного потока и рассмотрим отрезок, соответствующий этому символу. Этот отрезок разделим на части, пропорциональные частотам встречаемости символов.
- Повторим пункт (3) до конца входного потока.
- Выберем любое число из получившегося отрезка. Это и будет результат арифметического кодирования.
left = 0 // Левая граница [left; right) отрезка изначально равна 0 right = 1 // Правая граница [left; right) отрезка изначально равна 1 while !eof read(symb) newRight = left + (right - left) * segment[symb].right // segment[symb] — подотрезок отрезка [0; 1), соответствующий символу symb newLeft = left + (right - left) * segment[symb].left left = newLeft right = newRight ans = (left + right) / 2 // В качестве результата взята средняя точка отрезка [left; right)
Декодирование
Алгоритм по вещественному числу восстанавливает исходный текст.
- Выберем на отрезке , разделенном на части, длины которых равны вероятностям появления символов в тексте, подотрезок, содержащий входное вещественное число. Символ, соответствующий этому подотрезку, дописываем в ответ.
- Нормируем подотрезок и вещественное число.
- Повторим п. (1-2) до тех пор, пока не получим ответ (до конца файла).
do
for i = 1 to n
    if code >= segment[i].left && code < segment[i].right
        write(segment[i].character)
        code = (code – segment[i].left) / (segment[i].right – segment[i].left)
        break  
while (segment[i].character != eof)
Замечание
Ккодировщику и декодировщику должно быть известно, когда завершать работу. Для этого можно передавать в качестве аргумента длину текста или символ конца файла, после которого процесс должен быть остановлен.
Для оптимизации размера кода необходимо выбрать из окончательного диапазона число, содержащее наименьшее количество знаков в двоичной записи.
Пример работы
Рассмотрим в качестве примера строку
Кодирование
| Символ | Частота появления | 
|---|---|
| 
 | |
| 
 | |
| 
 | 
| Считанный символ | Левая граница отрезка | Правая граница отрезка | 
|---|---|---|
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | 
Код:
Декодирование
Код:
| Декодируемый символ | Код | 
|---|---|
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | 
Замечание
При декодировании текста можно не только нормализовывать рабочий отрезок и текущий код, но и уменьшать рабочий отрезок (аналогично кодированию), не изменяя значение кода.
Декодирование (второй способ)
Код:
| Декодируемый символ | Границы отрезка | |||
|---|---|---|---|---|
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
Оценка длины кодового слова
| Теорема: | 
| При арифметическом кодировании длина кодового слова не превышает энтропии исходного текста. | 
| Доказательство: | 
| Размер сообщения ( - длина текста; - размер алфавита; - частота встречаемости символа; - вероятность вхождения символа)Число бит в закодированном тексте: | 



