1. 程式人生 > >整數壓縮編碼 ZigZag

整數壓縮編碼 ZigZag

在分析Avro原始碼時,發現Avro為了對int、long型別資料壓縮,採用Protocol Buffers的ZigZag編碼(Thrift也採用了ZigZag來壓縮整數)。

1. 補碼編碼

為了便於後面的分析,我們先回顧下幾個概念:

  • 原碼:最高位為符號位,剩餘位表示絕對值;
  • 反碼:除符號位外,對原碼剩餘位依次取反;
  • 補碼:對於正數,補碼為其自身;對於負數,除符號位外對原碼剩餘位依次取反然後+1。

補碼解決了原碼中\(0\)存在兩種編碼的問題:

\[ 0=[0000 \enspace 0000]_原=[1000 \enspace 0000]_原 \]

補碼\([1000 \enspace 0001]_補\) 表示\(-128\);此外,原碼中還存在加法錯誤的問題:

\[ 1 + (-1) = [0000 \enspace 0001]_原 + [1000 \enspace 0001]_原 = [1000 \enspace 0010]原 = -2 \]

若用補碼,則可得到正確結果:

\[ 1 + (-1) = [0000 \enspace 0001]_補 + [1111 \enspace 1111]_補 = [0000 \enspace 0000]_補 = 0 \]

因此,在計算機儲存整數時,採用的是補碼。此外,整數的補碼有一些有趣的性質:

  • 左移1位(n << 1),無論正數還是負數,相當於乘以2;對於正數,若大於Integer.MAX_VALUE/2(1076741823),則會發生溢位,導致左移1位後為負數
  • 右移31位(n >> 31),對於正數,則返回0x00000000
    ;對於負數,則返回0xffffffff

這些性質正好在ZigZag編碼中用到了。

2. ZigZag

對於int值1,-1,20151103,均是用4 Bytes來表示:

\[ 1 = [00 \enspace 00 \enspace 00 \enspace 01] \\ -1 = [ff \enspace ff \enspace ff \enspace ff] \\ 20151103 = [01 \enspace 33 \enspace 7b \enspace 3f] \]

在《Huffman編碼》中證明了壓縮編碼應滿足:

高概率的碼字字長應不長於低概率的碼字字長

一般情況下,使用較多的是小整數,那麼較小的整數應使用更少的byte來編碼。基於此思想,ZigZag被提出來。

編碼

首先,ZigZag按絕對值升序排列,將整數hash成遞增的32位bit流,其hash函式為h(n) = (n << 1) ^ (n >> 31);對應地long型別(64位)的hash函式為(n << 1) ^ (n >> 63)。整數的補碼(十六進位制)與hash函式的對應關係如下:

n hex h(n) ZigZag (hex)
0 00 00 00 00 00 00 00 00 00
-1 ff ff ff ff 00 00 00 01 01
1 00 00 00 01 00 00 00 02 02
-2 ff ff ff fe 00 00 00 03 03
2 00 00 00 02 00 00 00 04 04
... ... ... ...
-64 ff ff ff c0 00 00 00 7f 7f
64 00 00 00 40 00 00 00 80 80 01
... ... ... ...

拿到hash值後,想當然的編碼策略:直接去掉hash值的前導0之後的byte作為壓縮編碼。但是,為什麼ZigZag(64)=8001呢?這涉及到編碼唯一可譯性的問題,只有當編碼為字首碼才能保證可譯,即

任意一碼字均不為其他碼字的字首

我們來看看,如果按上面的策略做壓縮編碼,則

h(0) = 0x0 = [00]
h(64) = 0x80 = [80]
h(16384) = 0x8000 = [80 00]

那麼,當收到位元組流[80 00]時,是應解碼為兩個整數64, 00,還是一個整數16384?因此,為了保證編碼的唯一可譯性,需要對hash值進行字首碼編碼,ZigZag採用瞭如下策略:

input: int n
output: byte[] buf

loop
    if 第七位滿1或有進位:
        n |= 0x80;
        取低位的8位作為一個byte寫入buf;
        n >>>=7(無符號右移7位,在高位插0);
    else:
        取低位的8位作為一個byte寫入buf
end

ZigZag編碼的Java實現(從org.apache.avro.io.BinaryData摳出來的):

/** Encode an integer to the byte array at the given position. Will throw
 * IndexOutOfBounds if it overflows. Users should ensure that there are at
 * least 5 bytes left in the buffer before calling this method.
 * @return The number of bytes written to the buffer, between 1 and 5.
 */
public static int encodeInt(int n, byte[] buf, int pos) {
// move sign to low-order bit, and flip others if negative
  n = (n << 1) ^ (n >> 31);
  int start = pos;
  if ((n & ~0x7F) != 0) {
    buf[pos++] = (byte)((n | 0x80) & 0xFF);
    n >>>= 7;
    if (n > 0x7F) {
      buf[pos++] = (byte)((n | 0x80) & 0xFF);
      n >>>= 7;
      if (n > 0x7F) {
        buf[pos++] = (byte)((n | 0x80) & 0xFF);
        n >>>= 7;
        if (n > 0x7F) {
          buf[pos++] = (byte)((n | 0x80) & 0xFF);
          n >>>= 7;
        }
      }
    }
  } 
  buf[pos++] = (byte) n;
  return pos - start;
}

ZigZag是一種變長編碼,當整數值較大時,hash值的十六進位制的有效位會較長,對應地ZigZag碼字會出現需要5 byte儲存;比如,

ZigZag(Integer.MAX_VALUE)=[fe ff ff ff 0f]

解碼

解碼為編碼的逆操作,首先,將ZigZag編碼還原成hash值,然後用hash函式\(h(n)\)的逆函式\(h^{-1}(n)\) = (n >>> 1) ^ -(n & 1)得到原始的整數值。Java程式碼實現(在avro原始碼org.apache.avro.io.BinaryDecoder中)如下:

public static int readInt(byte[] buf, int pos) throws IOException {
  int len = 1;
  int b = buf[pos] & 0xff;
  int n = b & 0x7f;
  if (b > 0x7f) {
    b = buf[pos + len++] & 0xff;
    n ^= (b & 0x7f) << 7;
    if (b > 0x7f) {
      b = buf[pos + len++] & 0xff;
      n ^= (b & 0x7f) << 14;
      if (b > 0x7f) {
        b = buf[pos + len++] & 0xff;
        n ^= (b & 0x7f) << 21;
        if (b > 0x7f) {
          b = buf[pos + len++] & 0xff;
          n ^= (b & 0x7f) << 28;
          if (b > 0x7f) {
            throw new IOException("Invalid int encoding");
          }
        }
      }
    }
  }
  pos += len;
  return (n >>> 1) ^ -(n & 1); // back to two's-complement
}

ZigZag總結如下:

  1. ZigZag僅從經驗出發,認為較小的整數會有較大的概率出現,故設計編碼策略:小整數對應的ZigZag碼字短,大整數對應的ZigZag碼字長。
  2. 但是,在特定的場景下,比如,要傳輸的整數為大整數居多,ZigZag編碼的壓縮效率就不理想了。

相關推薦

整數壓縮編碼 ZigZag

在分析Avro原始碼時,發現Avro為了對int、long型別資料壓縮,採用Protocol Buffers的ZigZag編碼(Thrift也採用了ZigZag來壓縮整數)。 1. 補碼編碼 為了便於後面的分析,我們先回顧下幾個概念: 原碼:最高位為符號位,剩餘位表示絕對值; 反碼:除符號位外,對原碼剩餘位

HNUSTOJ-1520 壓縮編碼

else 解決 ref stat 狀態 規則 記錄 mes names 1520: 壓縮編碼 時間限制: 1 Sec 內存限制: 2 MB提交: 107 解決: 54[提交][狀態][討論版] 題目描述   某工業監控設備不斷發回采樣數據。每個數據是一個整

1.視頻壓縮編碼綜述

信息 png 兩種 變換 pan 結果 產生 不同的 減少 1.預測編碼 一幅圖像由許多個像素點組成,大量的統計表明,同一副圖像中像素之間具有較強的相關性。兩個像素之間的距離越短,則其相關性越強。即兩個像素的值越接近。於是,人們可以利用這種像素間的相關性進行壓縮編碼 例

MPEG-4 壓縮編碼標準

好的 form 視頻 分享圖片 選擇 sha 互訪問 let 重構 文章轉自:http://www.cnblogs.com/CoderTian/p/8477021.html 1.MPEG-4標準概述 與MPEG1和MPEG2標準相比,MPEG-4 更加註重多媒體系統的交

數字影象處理技術之影象壓縮編碼

影象壓縮編碼是專門研究影象資料壓縮的技術,就是儘量減少表示資料影象所需要的資料量 目的:減少儲存空間、縮短傳輸時間 影象壓縮編碼從本質上來說就是對要處理的影象資料按照一定的規則進行變換和組合,從而達到以儘可能少的資料來表示儘可能多的資料資訊。 一、資料的冗餘與相關 1.資

使用DEFLATE壓縮演算法壓縮後,Base64編碼的方式傳輸經壓縮編碼的檔案內容

 1、先把檔案以流的方式InputStream讀入in.read(s, 0, in.available()); /** * 功能:將批量檔案內容使用DEFLATE壓縮演算法壓縮,Base64編碼生成字串並返回<br> * 適用到的交易:批量代付,批量代收,批量退貨&

ccf 201612-4 壓縮編碼

201612-4 試題名稱: 壓縮編碼 時間限制: 3.0s 記憶體限制: 256.0MB 問題描述: 問題描述   給定一段文字,已知單詞a1, a2, …, an出現的頻率分別t1, t2, …, tn。可以用01串給這些單詞編碼,即

高效的資料壓縮編碼方式 Protobuf

一. protocol buffers 是什麼? Protocol buffers 是一種語言中立,平臺無關,可擴充套件的序列化資料的格式,可用於通訊協議,資料儲存等。 Protocol buffers 在序列化資料方面,它是靈活的,高效的。相比於 XML 來說,Protocol buffers 更加小巧

貪心算法——Huffman 壓縮編碼的實現

放置 分享圖片 但是 角度 相交 str 歧義 大於等於 即使 1. 如何理解 “貪心算法” 假設我們有一個可以容納 100 Kg 物品的背包,可以裝各種物品。我們有以下 5 種豆子,每種豆子的總量和總價值都各不相同。怎樣裝才能讓背包裏豆子的總價值最大呢? 這個問題其實很

CCF CSP 壓縮編碼

試題編號: 201612-4 試題名稱: 壓縮編碼 時間限制: 3.0s 記憶體限制: 256.0MB 問題描述: 問題描述   給定一段文字,已知單詞a1, a2, …, an出現的頻率分別t1, t2, …, tn。可以用01串給這些單

基於matlab的LZW影象壓縮編碼

LZW壓縮 LZW壓縮(LZW compression)是一種由Abraham Lempel、Jacob Ziv和Terry Welch發明的基於表查尋演算法把檔案壓縮成小檔案的無失真壓縮方法。LZW壓縮使用的兩個常用檔案格式是用於網站的GIF圖象格式和TIFF

H264學習筆記(1):視訊壓縮編碼的基本原理

        陸陸續續學習H264有一段時間了,曾經以為自己可以在這方面大有作為,但是越是學習越發現,根本不存在能夠大幅度提升H264效能的方案,對於我這種水平的人來講。初次學習,概念的理解仍然很困難。在這裡我只是簡單淺顯的講一講我最近的讀書學習感想。        首先

CCF 壓縮編碼

一、試題 問題描述   給定一段文字,已知單詞a1, a2, …, an出現的頻率分別t1, t2, …, tn。可以用01串給這些單詞編碼,即將每個單詞與一個01串對應,使得任何一個單詞的編碼(對應的01串)不是另一個單詞編碼的字首,這種編碼稱為字首碼。

資料壓縮編碼方法

經典的資料壓縮演算法 三大類:預測編碼、變換編碼、統計編碼 常用的解除相關性的措施是預測和變換,其實質都是進行序列的對映。 一般,預測編碼有可能完全解除序列的相關性,但須確知序列的概率特性;變換編碼一般只解除向量內部的相關性,但它可有許多可供選擇的變換方法,以適應不同的信源

CCF201612-4 壓縮編碼(100分)

試題編號:    201612-4 試題名稱:    壓縮編碼 時間限制:    3.0s 記憶體限制:    256.0MB 問題描述:     問題描述   給定一段文字,已知單詞a1, a2, …, an出現的頻率分別t1, t2, …, tn。可以用01串給這些單詞編碼,即將每個單詞與一個01串對應,

CCF-CSP 201612-4壓縮編碼解題報告

CCF-CSP 201612-4壓縮編碼 標籤(空格分隔): CCF-CSP 1、問題描述 傳送門 2、題解 (1)引——石子合併問題 題目描述:在一個操場上擺放著一行共n

【H.264/AVC視訊編解碼技術詳解】一. 視訊資訊與壓縮編碼

《H.264/AVC視訊編解碼技術詳解》視訊教程已經在“CSDN學院”上線,視訊中詳述了H.264的背景、標準協議和實現,並通過一個實戰工程的形式對H.264的標準進行解析和實現,歡迎觀看! “紙上得來終覺淺,絕知此事要躬行”,只有自己按照標準文件以程式碼的形式

視訊壓縮編碼基本原理

http://blog.csdn.net/leixiaohua1020/article/details/28114081 本文介紹一下視訊壓縮編碼和音訊壓縮編碼的基本原理。其實有關視訊和音訊編碼的原理的資料非常的多,但是自己一直也沒有去歸納和總結一下,在這裡簡單總結一下,以作備忘。 1.視訊編碼基本原理 (

ccf壓縮編碼(石子排序,四邊形優化)

#include <iostream> #include <cstdio> using namespace std; const int maxn = 1005; const

視訊壓縮編碼問與答

1、什麼是H.261編碼協議        答:H.261是最早出現的視訊編碼建議,它採用的演算法結合了可減少時間冗餘的幀間預測和可減少空間冗餘的DCT變換的混合編碼方法,其輸出位元速率是p×64kbit/s。p取值較小時,只能傳清晰度不太高的影象,適合於面對面的電視電話;