なお、ゾーン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)は使用していません。
/// <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型に変換する際、桁あふれする場合がありますので、業務要件に応じて適切に処理してください。
/// <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の場合あり
}リンク
