なお、ゾーン10進数はこちらで紹介しています。
パック10進数
- ゾーン10進数の変換方法
- 10進数の各桁を「上位4ビットで1桁、下位4ビットで1桁」のバイトに変換して生成します。
- 生成したバイト列の最後の下位4ビットが符号部になっており、符号を示す値を設定します。
符号部の値は実行環境に依存する場合があります。IBM汎用機の場合、符号無しはF(1111)、正はC(1100)、負はD(1101)となります。
- 各文字コードにおける変換例を次に示します。
サンプル(整数) パック10進数(16進数) 123 12 3C -123 12 3D 1234 01 23 4C
C#によるサンプル
- .NET Core 3.1(C# 8.0)を使ったサンプルとなります。
- 実現方式として、算術演算・ビット演算を使用して数値ベースで変換を行う方式と、文字列操作で変換を行う方式が考えられます。ここでは、単純で分かりやすい、後者の「文字列操作で変換を行う方式」を使っています。
- 完全なソースコードはこちらで公開しています。
整数をパック10進数に変換
long型からパック10進数(バイト列)を生成するサンプルです。
整数を2桁毎に分割して16進数文字列を作成し、バイト列を生成しています。
符号があるlong型の使用を想定しているので、符号無しF(1111)は使用していません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | /// <summary> /// パック10進数: 符号部 正(ASCIIコード使用時) /// </summary> private const char PackedDecSignPartPlus = 'C'; // 0b_1100 /// <summary> /// パック10進数: 符号部 負(ASCIIコード使用時) /// </summary> private const char PackedDecSignPartMinus = 'D'; // 0b_1101 /// <summary> /// 整数からパック10進数を生成する。 /// </summary> /// <param name="num">整数</param> /// <returns>パック10進数</returns> public static byte[] CreatePackedDecimalBytes(long num) { var isPositive = num >= 0; var sb = new StringBuilder(num.ToString().TrimStart('-')); // -123 => 123 // 偶数桁の16進数文字列になるよう0を追加 // (後で符号部1桁を追加するので、ここでは奇数である必要がある。) if (sb.Length % 2 == 0) sb.Insert(0, '0'); // 符号部1桁を追加(16進数) sb.Append(isPositive ? PackedDecSignPartPlus : PackedDecSignPartMinus); // 文字列の各2桁を16進数としてバイトに変換する。 var str = sb.ToString(); return Enumerable.Range(0, str.Length) .Where(i => i % 2 == 0) .Select(i => Convert.ToByte(str.Substring(i, 2), 16)) .ToArray(); } |
パック10進数を整数に変換
パック10進数(バイト列)からlong型の整数を生成するサンプルです。
バイト列から16進数文字列を生成し、符号部を除いてそのまま10進数文字列としてlong型に変換します。
16進数文字列が数値以外(A-F)や、符号部が想定している値以外の場合は例外をスローしています。
整数文字列をlong型に変換する際、桁あふれする場合がありますので、業務要件に応じて適切に処理してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | /// <summary> /// パック10進数: 符号部 正(ASCIIコード使用時) /// </summary> private const char PackedDecSignPartPlus = 'C'; // 0b_1100 /// <summary> /// パック10進数: 符号部 負(ASCIIコード使用時) /// </summary> private const char PackedDecSignPartMinus = 'D'; // 0b_1101 /// <summary> /// パック10進数から整数を生成する。 /// </summary> /// <param name="bytes">パック10進数</param> /// <returns>整数</returns> public static long ParsePackedDecimal(byte[] bytes) { // 16進数文字列を生成 var hexes = BitConverter.ToString(bytes).Replace("-", ""); // 1F-34 => 1F34 // 数値以外(a-f)が含まれないことを検証 var numstr = hexes[0..^1]; foreach (var c in numstr) if (c < '0' || '9' < c) throw new ArgumentException($"不正な数値部: {hexes}"); // 符号部が想定される符号値であることを検証 var signstr = hexes[^1]; if (signstr == PackedDecSignPartMinus) numstr = "-" + numstr; else if (signstr != PackedDecSignPartPlus) throw new ArgumentException($"不正な符号部: {hexes}"); return long.Parse(numstr); // OverflowExceptionの場合あり } |
リンク