Google Code Prettify

2015年5月10日 星期日

BCD pack & unpack

在程式裡的 I/O 和 CPU 計算比起來,速度差距非常大,網路傳輸又是 I/O  中比較慢的一種,所以,常可見到網路傳輸的資料,會先經過壓縮後再傳輸,接收端接到後再解壓縮。BCD 是一種常用的壓縮技術,當要傳輸的資料中,某一段確定是數字,即可將該段的資料以 BCD 壓縮後傳輸,例如:
123456789665,或許它代表著12點34分56秒789毫秒665奈秒,如果不壓縮直接傳就是 12 個 bytes,BCD 則只會有 6 個 bytes,為什麼? 說明如下:
  1. 一個 byte 有 8 個 bits,用來存數字,實際上只會用到後面 4 個 bits,前面的 4 個 bits 永遠為 0000,例如 5 的 8 個 bits 會是 00000101 (二進位表示法),9 的 8 bits 為 00001001。
  2. BCD 用一個 byte 來存兩個數字,前 4 個 bits (高位元) 存一個數字,後 4 個 bits 再存一個數字,所以,如果有兩個數字 95,用 BCD 儲存就會是 10010101,前 4 個 bits 是 9,後 4 個 bits 是 5。
底下是 BCD 的程式:

public class BCD {
 static public byte[] pack(long number) {
  byte hi, lo;
  String s = String.valueOf(number);
  byte[] data = s.getBytes();
  byte[] bcd = new byte[s.length() / 2];
  for (int i = 0; i < bcd.length; i++) {
   hi = (byte)(data[i * 2] << 4);
   lo = (byte)(data[i * 2 + 1] & 0x0f);
   bcd[i] = (byte)(hi | lo);
  }
  return bcd;
 }
 static public long unpack(byte[] pack, byte[] data) {
  byte hi, lo;
  long number = 0L;
  for (int i = 0; i < pack.length; i++) {
   hi = (byte)((pack[i] >> 4) & 0x0f);
   lo = (byte)(pack[i] & 0x0f);
   data[i * 2] = hi;
   data[i * 2 + 1] = lo;
   number = number * 100 + (hi * 10) + lo;
  }
  return number;
 }
}

應該很容易看的懂,pack 就是將正常的資料壓縮成 BCD 格式,unpack 是將 BCD 格式的資料還原。測試程式如下:
要被壓縮的資料為 number,值為 123456789665,參考下面的輸出,可以看到 BCD 長度只有 6 bytes,其 hex 值即是我們要傳輸的值; 把 BCD 資料解壓縮,即可回 number 的值。
bcd len: 6
bcd value: [B@439f5b3d
bcd value (hex): 123456789665
data len: 12
data value: [B@685f4c2e
data value (hex) 010203040506070809060605
number: 123456789665
要特別注意的是,上面 unpack 程式中,高位元的資料在向左 shift 4 位到低位元後,一定要再 & 0x0f,將高位元清為 0,因為 shift 時,如果最高的 bit 為 1,往左 shift 4 位,高位的 4 個 bits 會全部變成 1,例如最前面例子舉的 95,二進位是 10010101,5 是存在低位元,只要將高位元清成0 ( & 0x0f),即可得到 5,但是 高位元的 9 向左 shift 4 位後會是 11111001,所以要將高位元再清為 0 (& 0x0f)。

沒有留言:

張貼留言