Гамма-код Элиаса: различия между версиями

м (45 версий импортировано: Импорт из Википедии)
 
(не показано 28 промежуточных версий 20 участников)
Строка 4: Строка 4:
 
Чтобы закодировать число:
 
Чтобы закодировать число:
 
# Записать его в двоичной форме.
 
# Записать его в двоичной форме.
# Перед двоичным представлением числа дописать нули. Количество нолей на единицу меньше количества битов двоичного представления числа.
+
# Перед двоичным представлением числа дописать нули. Количество нулей на единицу меньше количества битов двоичного представления числа.
  
 
Аналогичный способ описания этого процесса:
 
Аналогичный способ описания этого процесса:
# Разделить целое число на самую большую степень 2, которую оно включает (2<sup>N</sup>), и на оставшиеся N двоичных цифр от данного целого числа.
+
# Выделить из целого числа старший значащий бит (самую большую степень 2, которую число включает — 2<sup>N</sup>) и младшие N бит.
# Записать N в унарном коде; то есть N нолей, следующих за единицей.
+
# Записать N в унарном коде; то есть N нолей, за которыми следует единица.
# Присоединить оставшиеся N двоичных цифр к этому представлению N.
+
# Дописать N младших двоичных цифр числа следом за этим унарным кодом.
  
 
Начало кодирования:
 
Начало кодирования:
Строка 18: Строка 18:
 
| 1 || 2<sup>0</sup> + 0 || 1 || 1/2
 
| 1 || 2<sup>0</sup> + 0 || 1 || 1/2
 
|-
 
|-
| 2 || 2<sup>1</sup> + 0 || 01 0 || 1/8
+
| 2 || 2<sup>1</sup> + 0 || 0 1 0 || 1/8
 
|-
 
|-
| 3 || 2<sup>1</sup> + 1 || 01 1 || 1/8
+
| 3 || 2<sup>1</sup> + 1 || 0 1 1 || 1/8
 
|-
 
|-
| 4 || 2² + 0 || 001 00 || 1/32
+
| 4 || 2² + 0 || 00 1 00 || 1/32
 
|-
 
|-
| 5 || 2² + 1 || 001 01 || 1/32
+
| 5 || 2² + 1 || 00 1 01 || 1/32
 
|-
 
|-
| 6 || 2² + 2 || 001 10 || 1/32
+
| 6 || 2² + 2 || 00 1 10 || 1/32
 
|-
 
|-
| 7 || 2² + 3 || 001 11 || 1/32
+
| 7 || 2² + 3 || 00 1 11 || 1/32
 
|-
 
|-
| 8 || 2³ + 0 || 0001 000 || 1/128
+
| 8 || 2³ + 0 || 000 1 000 || 1/128
 
|-
 
|-
| 9 || 2³ + 1 || 0001 001 || 1/128
+
| 9 || 2³ + 1 || 000 1 001 || 1/128
 
|-
 
|-
|10 || 2³ + 2 || 0001 010 || 1/128
+
|10 || 2³ + 2 || 000 1 010 || 1/128
 
|-
 
|-
|11 || 2³ + 3 || 0001 011 || 1/128
+
|11 || 2³ + 3 || 000 1 011 || 1/128
 
|-
 
|-
|12 || 2³ + 4 || 0001 100 || 1/128
+
|12 || 2³ + 4 || 000 1 100 || 1/128
 
|-
 
|-
|13 || 2³ + 5 || 0001 101 || 1/128
+
|13 || 2³ + 5 || 000 1 101 || 1/128
 
|-
 
|-
|14 || 2³ + 6 || 0001 110 || 1/128
+
|14 || 2³ + 6 || 000 1 110 || 1/128
 
|-
 
|-
|15 || 2³ + 7 || 0001 111 || 1/128
+
|15 || 2³ + 7 || 000 1 111 || 1/128
 
|-
 
|-
|16 || 2<sup>4</sup> + 0 || 00001 0000 || 1/512
+
|16 || 2<sup>4</sup> + 0 || 0000 1 0000 || 1/512
 
|-
 
|-
|17 || 2<sup>4</sup> + 1 || 00001 0001 || 1/512
+
|17 || 2<sup>4</sup> + 1 || 0000 1 0001 || 1/512
 
|-
 
|-
 
|… || || ||
 
|… || || ||
Строка 58: Строка 58:
  
 
# Считать все нули, встречающиеся до первой 1. Пусть N — количество этих нулей.
 
# Считать все нули, встречающиеся до первой 1. Пусть N — количество этих нулей.
# Принимая во внимание единицу, которая была достигнута как первая цифра целого числа, со значением 2<sup>N</sup>, считать оставшиеся N цифр целого числа.
+
# Принимая во внимание единицу, которая станет первым (самая значащим) битом целого числа, со значением 2<sup>N</sup>, считать оставшиеся N цифр целого числа.
  
 
Гамма-кодирование используется в приложениях, где самое большое значение не может быть известно заранее, или чтобы сжать данные, в которых маленькие значения встречаются более часто чем большие.
 
Гамма-кодирование используется в приложениях, где самое большое значение не может быть известно заранее, или чтобы сжать данные, в которых маленькие значения встречаются более часто чем большие.
Строка 64: Строка 64:
 
== Обобщение ==
 
== Обобщение ==
 
<!-- на этот заголовок есть ссылки из других статей -->
 
<!-- на этот заголовок есть ссылки из других статей -->
Гамма-кодирование не подходит для кодирования нулевых значений или отрицательных чисел. Единственный способ закодировать ноль — прибавить к нему 1 до кодирования и отнять после декодирования. Другой способ — приписать в начале любой ненулевой код с 1 , а затем кодировать ноль как простой 0. Единственный способ закодировать все положительные числа — перед началом кодирования установить [[биекция|биекцию]] (соответствие), отображая целые числа из (0, 1, −1, 2, −2, 3, −3, …) в (1, 2, 3, 4, 5, 6, 7, …).
+
Гамма-кодирование не подходит для кодирования нулевых значений или отрицательных чисел. Один из способов закодировать ноль — прибавить ко всем числам 1 до кодирования и отнять после декодирования. Другой способ — приписать в начале любого ненулевого кода 1 , а затем кодировать ноль как простой 0. Единственный способ закодировать все целые числа — перед началом кодирования установить [[биекция|биекцию]] (соответствие), отображая целые числа из (0, 1, −1, 2, −2, 3, −3, …) в (1, 2, 3, 4, 5, 6, 7, …).
  
 
== Пример программного кода ==
 
== Пример программного кода ==
Строка 73: Строка 73:
 
     IntReader intreader(source);
 
     IntReader intreader(source);
 
     BitWriter bitwriter(dest);
 
     BitWriter bitwriter(dest);
 
+
     while(intreader.hasLeft())
     while (intreader.hasLeft())    
 
 
     {
 
     {
 
       int num = intreader.getInt();
 
       int num = intreader.getInt();
       int numberBits = log2(num);
+
       int l = log2(num);
 
+
       for (int a=0; a < l; a++)
      // поместить l нулей, чтобы показать, сколько бит будут следовать
 
       for (int a = numberBits - 1; a >= 0; a--)
 
 
       {       
 
       {       
           bitwriter.putBit(false);
+
           bitwriter.putBit(false); //поместить нули, чтобы показать, сколько бит будут следовать
 
       }
 
       }
 
+
       bitwriter.putBit(true); //пометить конец нолей
       // скопировать (numberBits + 1) битов числа
+
       for (int a = l-1; a >= 0; a--) //записать биты как простые двоичные числа
       for (int a = numberBits; a >= 0; a--)
 
 
       {
 
       {
 
           if (num & (1 << a))
 
           if (num & (1 << a))
              bitwriter.putBit(true);
+
            bitwriter.putBit(true);
 
           else
 
           else
              bitwriter.putBit(false);
+
            bitwriter.putBit(false);
 
       }
 
       }
 
     }
 
     }
 
 
     intreader.close();
 
     intreader.close();
 
     bitwriter.close();
 
     bitwriter.close();
 
}
 
}
 
 
// Декодирование
 
// Декодирование
 
void eliasGammaDecode(char* source, char* dest)
 
void eliasGammaDecode(char* source, char* dest)
 
{
 
{
 
     BitReader bitreader(source);
 
     BitReader bitreader(source);
     IntWriter intwriter(dest);
+
     BitWriter bitwriter(dest);
 
+
    int numberBits = 0;
     while (bitreader.hasLeft())
+
     while(bitreader.hasLeft())
 
     {
 
     {
         int numberBits = 0;
+
         while(!bitreader.getBit() || bitreader.hasLeft())numberBits++; //продолжить чтение пока не встретится единица...
 
+
         int current = 0;
        // продолжить чтение пока не встретится единица...
+
         for (int a=0; a < numberBits; a++) //прочитать numberBits битов
         while (bitreader.getBit() == false)
 
         {
 
            numberBits++;
 
 
 
            if (!bitreader.hasLeft())
 
            {
 
                // неожиданный конец потока битов
 
                // аварийный выход
 
                // игнорируем уже прочитанные биты
 
                return;
 
            }
 
        }
 
 
 
        if (numberBits > (sizeof(int) * BITS_PER_BYTE - 1))
 
 
         {
 
         {
             // переполнение целочисленного типа
+
             if (bitreader.getBit())
            // входной поток содержит неверные данные
+
              current += 1 << a;
            // аварийный выход
 
            // игнорируем уже прочитанные биты
 
            return;
 
 
         }
 
         }
 
+
        //записать его как 32-битное число
         int num = 1;
+
 
+
         current = current | ( 1 << numberBits ) ;//последний бит не декодируется!
        // прочитать numberBits битов
+
         for (int a=0; a < 32; a++) //прочитать numberBits битов
         for (; numberBits > 0; numberBits--)
 
 
         {
 
         {
             if (!bitreader.hasLeft())
+
             if (current & (1 << a))
            {
+
              bitwriter.putBit(true);
                // неожиданный конец потока битов
+
             else
                // аварийный выход
+
              bitwriter.putBit(false);
                // игнорируем уже прочитанные биты
 
                return;
 
             }
 
 
 
            num = num << 1;
 
 
 
            if (bitreader.getBit() == true)
 
              num = num | 1;
 
 
         }
 
         }
 
        intwriter.putInt(num);
 
 
     }
 
     }
 
    intreader.close();
 
    bitwriter.close();
 
 
}
 
}
 
</source>
 
</source>
Строка 162: Строка 125:
 
* [[Омега-код Элиаса]]
 
* [[Омега-код Элиаса]]
 
* [[Дельта-код Элиаса]]
 
* [[Дельта-код Элиаса]]
 +
== Литература ==
 +
* {{статья |author-first=Peter |author-last=Elias |заглавие=Universal codeword sets and representations of the integers |издание={{Нп3|IEEE Transactions on Information Theory}} |том=21 |номер=2 |страницы=194—203 |ссылка=http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=1055349 |doi=10.1109/tit.1975.1055349 |язык=en |тип=journal |месяц=3 |год=1975}}
 +
 +
{{Методы сжатия}}
  
 
[[Категория:Алгоритмы сжатия без потерь]]
 
[[Категория:Алгоритмы сжатия без потерь]]
 
[[cs:Eliasovo gama kódování]]
 
[[en:Elias gamma coding]]
 
[[ja:ガンマ符号]]
 
[[ko:엘리어스 감마 부호]]
 

Текущая версия от 00:51, 20 августа 2025

Гамма-код Элиаса — это универсальный код для кодирования положительных целых чисел, разработанный Питером Элиасом. Он обычно используется при кодировании целых чисел, максимальное значение которых не может быть определено заранее.

Описание алгоритмаПравить

Чтобы закодировать число:

  1. Записать его в двоичной форме.
  2. Перед двоичным представлением числа дописать нули. Количество нулей на единицу меньше количества битов двоичного представления числа.

Аналогичный способ описания этого процесса:

  1. Выделить из целого числа старший значащий бит (самую большую степень 2, которую число включает — 2N) и младшие N бит.
  2. Записать N в унарном коде; то есть N нолей, за которыми следует единица.
  3. Дописать N младших двоичных цифр числа следом за этим унарным кодом.

Начало кодирования:

Число Значение Кодирование Предполагаемая
вероятность
1 20 + 0 1 1/2
2 21 + 0 0 1 0 1/8
3 21 + 1 0 1 1 1/8
4 2² + 0 00 1 00 1/32
5 2² + 1 00 1 01 1/32
6 2² + 2 00 1 10 1/32
7 2² + 3 00 1 11 1/32
8 2³ + 0 000 1 000 1/128
9 2³ + 1 000 1 001 1/128
10 2³ + 2 000 1 010 1/128
11 2³ + 3 000 1 011 1/128
12 2³ + 4 000 1 100 1/128
13 2³ + 5 000 1 101 1/128
14 2³ + 6 000 1 110 1/128
15 2³ + 7 000 1 111 1/128
16 24 + 0 0000 1 0000 1/512
17 24 + 1 0000 1 0001 1/512

Распределение предполагаемых вероятностей для кодов добавлено для ясности.

Чтобы декодировать закодированное гамма-кодом Элиаса число следует:

  1. Считать все нули, встречающиеся до первой 1. Пусть N — количество этих нулей.
  2. Принимая во внимание единицу, которая станет первым (самая значащим) битом целого числа, со значением 2N, считать оставшиеся N цифр целого числа.

Гамма-кодирование используется в приложениях, где самое большое значение не может быть известно заранее, или чтобы сжать данные, в которых маленькие значения встречаются более часто чем большие.

ОбобщениеПравить

Гамма-кодирование не подходит для кодирования нулевых значений или отрицательных чисел. Один из способов закодировать ноль — прибавить ко всем числам 1 до кодирования и отнять после декодирования. Другой способ — приписать в начале любого ненулевого кода 1 , а затем кодировать ноль как простой 0. Единственный способ закодировать все целые числа — перед началом кодирования установить биекцию (соответствие), отображая целые числа из (0, 1, −1, 2, −2, 3, −3, …) в (1, 2, 3, 4, 5, 6, 7, …).

Пример программного кодаПравить

// Кодирование
void eliasGammaEncode(char* source, char* dest)
{
     IntReader intreader(source);
     BitWriter bitwriter(dest);
     while(intreader.hasLeft())
     {
      int num = intreader.getInt();
      int l = log2(num);
      for (int a=0; a < l; a++)
      {       
          bitwriter.putBit(false); //поместить нули, чтобы показать, сколько бит будут следовать
      }
      bitwriter.putBit(true); //пометить конец нолей
      for (int a = l-1; a >= 0; a--) //записать биты как простые двоичные числа
      {
          if (num & (1 << a))
             bitwriter.putBit(true);
          else
             bitwriter.putBit(false);
      }
     }
     intreader.close();
     bitwriter.close();
}
// Декодирование
void eliasGammaDecode(char* source, char* dest)
{
     BitReader bitreader(source);
     BitWriter bitwriter(dest);
     int numberBits = 0;
     while(bitreader.hasLeft())
     {
        while(!bitreader.getBit() || bitreader.hasLeft())numberBits++; //продолжить чтение пока не встретится единица...
        int current = 0;
        for (int a=0; a < numberBits; a++) //прочитать numberBits битов
        {
            if (bitreader.getBit())
               current += 1 << a;
        }
        //записать его как 32-битное число
 
        current = current | ( 1 << numberBits ) ;//последний бит не декодируется!
        for (int a=0; a < 32; a++) //прочитать numberBits битов
        {
            if (current & (1 << a))
               bitwriter.putBit(true);
            else
               bitwriter.putBit(false);
        }
     }
}

См. такжеПравить

ЛитератураПравить

Ошибка Lua в Модуль:Navbox на строке 353: attempt to index local 'listText' (a nil value).