最近パック数値なるものを扱う機会があったので、忘れないようにメモ。
パック数値とは?
- 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