2010年2月20日土曜日

パック数値とは?


最近パック数値なるものを扱う機会があったので、忘れないようにメモ。

パック数値とは?

  • 1バイトの数字を4ビットで表現する数値のこと。ゾーン数値と比べて単純計算ではあるが、使用容量が半分ですむ。
  • パック数値には、符号なしパックと符号ありパックが存在する。
  • 符号のあらわし方は、末尾の4ビットで表現する。符号なしの場合でも、末尾4ビットで符号なしであることを設定する必要あり。
  • 末尾4ビットが必ず符号領域となるため、ゾーン数値で表した場合の桁数は奇数となる。

【ゾーン数値とパック数値の比較】

10進数数値 ゾーン数値(JISの場合) 符号なしパック 符号ありパック
12345 0x3132333435
(5バイト)
0x12345F
(3バイト)
0x12345C
(3バイト)
+12345 0x31323334C5
(5バイト)
- 0x12345C
(3バイト)
-12345 0x31323334D5
(5バイト)
- 0x12345D
(3バイト)
上記表でも分かるとおり、符合なしは0xFで表現され、プラスは0xC、マイナスは0xDで表現される。

パック数値をアンパックするソース

Javaの場合

// 呼び出し例
// unpack(new byte[]{0x01, 0x2F});  -> 12
// unpack(new byte[]{0x00, 0x00, 0x33, 0x44, 0x0D}); -> -33440
public static long unpack(byte[] pack) {
    long num = 0;
    int weight = 1;
    for (int i = pack.length - 1; i >= 0; i--) {
        num += (pack[i] >> 4) * weight;
        weight *= 10;
        if (i != 0) {
            num += (pack[i - 1] & 0x0F) * weight;
            weight *= 10;
        }
    }
    byte sign= (byte) (pack[pack.length - 1] & 0x0F);
    if (sign == 0x0F || sign == 0x0C) {
        // nop
    } else if (sign == 0x0D) {
        num *= -1;
    } else {
        throw new IllegalArgumentException("invalid sign");
    }
    return num;
}

ruby

def self.un_pack(pack)
  sprintf("%X", pack).gsub(/^(.+)(.)$/) {|str|
    case $2
      when "F", "C"
        ""
      when "D"
        "-"
      else
        raise RuntimeError.new("illegal sign. sign = [#{$2}]")
    end + $1
  }.to_i
end