最近パック数値なるものを扱う機会があったので、忘れないようにメモ。
パック数値とは?
- 1バイトの数字を4ビットで表現する数値のこと。ゾーン数値と比べて単純計算ではあるが、使用容量が半分ですむ。
- パック数値には、符号なしパックと符号ありパックが存在する。
- 符号のあらわし方は、末尾の4ビットで表現する。符号なしの場合でも、末尾4ビットで符号なしであることを設定する必要あり。
- 末尾4ビットが必ず符号領域となるため、ゾーン数値で表した場合の桁数は奇数となる。
【ゾーン数値とパック数値の比較】
10進数数値 | ゾーン数値(JISの場合) | 符号なしパック | 符号ありパック |
12345 | 0x3132333435 (5バイト) |
0x12345F (3バイト) |
0x12345C (3バイト) |
+12345 | 0x31323334C5 (5バイト) |
- | 0x12345C (3バイト) |
-12345 | 0x31323334D5 (5バイト) |
- | 0x12345D (3バイト) |
パック数値をアンパックするソース
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