Mari kita lihat cara berpikir yang sedikit berbeda tentang pengkodean Huffman.
Misalkan Anda memiliki alfabet tiga simbol, A, B, dan C, dengan probabilitas 0,5, 0,25, dan 0,25. Karena probabilitasnya adalah semua kekuatan terbalik dari dua, ini memiliki kode Huffman yang optimal (yaitu identik dengan pengkodean aritmatika). Kami akan menggunakan kode kanonik 0, 10, 11 untuk contoh ini.
Misalkan negara kita adalah bilangan bulat besar, yang akan kita sebut . Anda dapat menganggap penyandian sebagai fungsi yang mengambil status saat ini, dan simbol untuk menyandikan, dan mengembalikan status baru:s
encode(s,A)encode(s,B)encode(s,C)=2s=4s+2=4s+3
Jadi mari kita mulai dengan negara 11 (yang 1011 dalam biner), menyandikan simbol B. Negara baru adalah 46, yang 101110 dalam biner. Seperti yang Anda lihat, ini adalah keadaan "lama" dengan urutan 10 ditambahkan di akhir. Kami memiliki dasarnya "output" urutan bit 10.
Sejauh ini baik.
Sekarang pikirkan sejenak tentang bagaimana pengkodean aritmatika bekerja. Jika Anda meletakkan probabilitas di atas penyebut umum, simbol A sebenarnya mewakili rentang , simbol B mewakili rentang dan simbol C mewakili kisaran .[04,24)[24,34)[34,44)
Pada dasarnya apa yang kita lakukan di sini adalah mengalikan semuanya dengan penyebut yang sama. Bayangkan bahwa keadaan sebenarnya dalam basis 4. Pengkodean simbol B benar-benar mengeluarkan angka 2 di basis itu, dan pengkodean simbol C menghasilkan keluaran angka 3 di basis itu.
Namun, simbol A sedikit berbeda, karena bukan seluruh digit pada basis 4.
Sebagai gantinya, kita dapat menganggap alfabet sebagai himpunan simbol A_0, A_1, B, C, dengan probabilitas yang sama. Ini, sekali lagi, memiliki kode Huffman optimal 00, 01, 10, 11. Atau, sekali lagi, kita dapat memikirkan hal ini di basis 4. Untuk menyandikan simbol, kita cukup melakukan:
encode(s,A0)encode(s,A1)encode(s,B)encode(s,C)=4s+0=4s+1=4s+2=4s+3
Jadi sekarang sudah jelas bagaimana cara menyandikan simbol B dan C, tetapi untuk menyandikan simbol A, kita punya pilihan. Manakah dari dan harus kita gunakan?A 1A0A1
Sekarang inilah ide cerdas: kita mencuri satu bit informasi dari negara :s
i=smod2
s′=⌊s2⌋
i=smod2
dan kemudian .encode(s′,Ai)
Dengan menggunakan contoh kami sebelumnya, , kami menemukan bahwa dan , dan kemudian . Status baru adalah 10101 dalam bentuk biner.s=11s′=5i=1encode(5,A1)=4×5+1=21
Sekarang ini tidak menghasilkan keluaran bit yang persis sama dengan pengkodean Huffman, tetapi menghasilkan keluaran yang memiliki panjang yang sama. Dan saya harap Anda dapat melihat bahwa ini juga dapat diuraikan secara unik. Untuk mendekode simbol, kita mengambil sisanya ketika dibagi dengan 4. Jika nilainya 2 atau 3, maka simbolnya masing-masing adalah B atau C. Jika 0 atau 1, maka simbolnya adalah A, dan kemudian kita dapat mengembalikan sedikit informasi dengan mengalikan status dengan 2 dan menambahkan 0 atau 1.
Yang menyenangkan tentang pendekatan ini adalah bahwa ia meluas secara alami ke pengkodean fraksional-bit, ketika pembilang dan / atau penyebut probabilitas tidak kekuatan dua. Misalkan kita memiliki dua simbol, A dan B, di mana probabilitas A adalah dan probabilitas B adalah . Kemudian kita dapat menyandikan simbol dengan: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
Untuk menyandikan simbol A, kita ambil dan , lalu .i=smod3encode(s′,Ai)s′=⌊s3⌋i=smod3encode(s′,Ai)
Ini setara dengan pengkodean aritmatika. Ini sebenarnya keluarga metode yang dikenal sebagai Sistem Angka Asimetris , dan dikembangkan selama beberapa tahun terakhir oleh Jarek Duda. Arti nama harus jelas: untuk menyandikan simbol dengan probabilitas , Anda secara konseptual mencuri digit basis-p dari negara, dan kemudian menambahkan digit basis-q. Asimetri berasal dari menafsirkan negara sebagai angka dalam dua basis yang berbeda.pq
Alasan mengapa itu adalah keluarga metode pengkodean adalah bahwa apa yang kami lihat di sini tidak praktis dengan sendirinya; diperlukan beberapa modifikasi untuk menghadapi kenyataan bahwa Anda mungkin tidak memiliki bilangan bulat presisi tak terbatas untuk memanipulasi variabel keadaan secara efisien, dan ada berbagai cara yang dapat Anda lakukan untuk mencapai hal ini. Pengkodean aritmatika, tentu saja, memiliki masalah serupa dengan ketepatan untuk kondisinya.
Varian praktis termasuk rANS ("r" berarti "rasio") dan tANS ("table-driven").
ANS memiliki beberapa keunggulan menarik dibandingkan pengkodean aritmatika, baik yang praktis maupun teoritis:
- Tidak seperti pengkodean aritmatika, "negara" adalah satu kata, bukan sepasang kata.
- Tidak hanya itu, tetapi encoder ANS dan dekoder yang sesuai memiliki status yang identik dan operasinya sepenuhnya simetris. Ini memunculkan beberapa kemungkinan menarik, seperti Anda dapat menyisipkan berbagai aliran simbol yang disandikan dan semuanya disinkronkan dengan sempurna.
- Implementasi praktis perlu, tentu saja, untuk "menampilkan" informasi saat Anda pergi, dan tidak hanya mengumpulkannya dalam bilangan bulat besar untuk ditulis di akhir. Namun, ukuran "output" dapat dikonfigurasi dengan imbalan kerugian kompresi (biasanya sederhana). Jadi di mana coders aritmatika harus menampilkan sedikit demi sedikit, ANS dapat menampilkan byte atau nybble pada suatu waktu. Ini memberi Anda tradeoff langsung antara kecepatan dan kompresi.
- Tampaknya hampir secepat pada perangkat keras generasi saat ini sebagai pengkodean aritmatika biner, dan karenanya bersaing dengan pengkodean Huffman. Ini membuatnya jauh lebih cepat daripada pengkodean aritmatika alfabet besar dan variannya (mis. Pengkodean rentang).
- Tampaknya bebas paten.
Saya tidak berpikir saya akan melakukan pengkodean aritmatika lagi.