メインフレームの心臓部:PL/IにおけるFIXED DECIMALと「パック10進数」の深淵
若手エンジニアからよく受ける相談がある。「なぜ、今どきPL/Iなのか? なぜ、わざわざ浮動小数点ではなくパック10進数を使うのか?」と。
答えは単純だ。我々が扱っているのは、一円の誤差も許されない金融や公共の基幹システムだからだ。コンピュータ内部でバイナリ(二進数)変換を行う浮動小数点は、循環小数による微細な誤差を避けて通れない。しかし、`FIXED DECIMAL(p,q)`は違う。これは人間が電卓を叩く感覚そのままに、10進数を10進数としてメモリ上に焼き付ける。
今日は、メインフレームのバッチ改修で必ず直面する「パック10進数」の正体と、その実務的な制御について語ろう。
—
1. パック10進数(COMP-3)の内部構造
`FIXED DECIMAL(p,q)`は、IBMメインフレームの世界では一般的に「COMP-3」形式で保持される。1バイトに2つの数字を詰め込み、最後の4ビット(ニブル)に符号(正ならC、負ならDなど)を置く。
例えば、`FIXED DECIMAL(5,2)`で「123.45」を定義した場合、メモリ上では以下のように表現される。
- 01 23 45 C (16進数表記)
この「人間がメモリを覗いた時に数字がそのまま読める」という特性こそが、ダンプ解析時に我々を救う命綱となる。浮動小数点の複雑怪奇な指数表現と格闘した経験がある者なら、この直感的な構造のありがたみが分かるはずだ。
2. 精度保持ルール:演算の罠を回避せよ
PL/Iのコンパイラは非常に優秀だが、演算時の精度保持ルールを理解していないと、中間結果で意図しない切り捨てが発生する。
特に、`FIXED DECIMAL`同士の演算では、以下の原則が働く。
- 加減算: 結果の精度はオペランドの最大値に合わせられる。
- 乗算: 精度は各オペランドの精度の和になる。
ここで重要なのは、「代入先(ターゲット)の変数の桁数」が、演算結果を保持できるだけの余裕を持っているかだ。中途半端な桁数定義をしていると、コンパイラは警告もなく上位桁を切り捨てる。これがバッチ改修で「なぜか合計金額が合わない」という怪奇現象の元凶となる。
3. 実践的なコーディング例
以下に、VSAMファイルからレコードを読み込み、パック10進数を用いて計算を行う標準的な構成を示す。
1
/ —————————————————————— /
/ PROGRAM: CALC_DEMO /
/ PURPOSE: パック10進数を用いた金額計算とエラーハンドリング /
/ —————————————————————— /
DEMO_PROC: PROCEDURE OPTIONS(MAIN);
/ VSAMファイルのレコード定義(パック10進数を使用) /
DCL 1 IN_REC,
5 CUST_ID CHAR(5),
5 UNIT_PRICE FIXED DEC(7, 2), / 単価:最大99,999.99 /
5 QTY FIXED DEC(5, 0); / 数量:最大99,999 /
/ 計算結果用変数:桁あふれを防ぐため十分な精度を確保 /
DCL TOTAL_AMT FIXED DEC(13, 2) INIT(0);
/ ONユニット:オーバーフロー発生時の制御 /
ON FIXEDOVERFLOW BEGIN;
PUT SKIP LIST(‘!!! 桁あふれ発生:計算処理を中断します !!!’);
SIGNAL CONDITION(ERR_ABEND);
END;
/ ファイル読み込み(擬似コード) /
READ FILE(INPUT_VSAM) INTO(IN_REC);
/ 計算処理:BUILTIN関数を使用して安全に算出 /
/ 10進数演算は、桁の定義さえ守れば極めて正確 /
TOTAL_AMT = UNIT_PRICE QTY;
PUT SKIP LIST(‘CUSTOMER: ‘ || CUST_ID || ‘ TOTAL: ‘ || TOTAL_AMT);
END DEMO_PROC;
4. 現場の教訓:デバッグのコツ
実務でのトラブルシューティングにおいて、私が常に意識していることは以下の3点だ。
1. ON FIXEDOVERFLOWを軽視するな:
大規模バッチで計算ミスが発生すると、遡及的な修正は地獄を見る。必ず演算の入り口で`FIXEDOVERFLOW`を監視し、異常検知時には即座にログを吐いて異常終了するように設計する。
2. 型変換を自動に任せるな:
`FIXED DEC`と`FLOAT`を混ぜるな。変換時に必ず精度が落ちる。計算の際は、すべての変数を`FIXED DEC`に統一し、必要であれば`DECIMAL`ビルトイン関数で明示的に変換せよ。
3. ダンプを恐れるな:
`COMP-3`は人間が読める。画面上の数値とメモリ上の16進数を比較する癖をつければ、どんな複雑なバグも必ず突き止められる。
最後に
PL/Iは古い言語かもしれないが、その堅牢性は現代のどの言語よりも「ビジネス計算」という一点において優れている。パック10進数の内部構造を支配することは、メインフレームのアーキテクトとしての一歩だ。
この記事を読んでいる君が、次回のバッチ改修で桁落ちの恐怖に怯えることなく、自信を持ってコードを書き上げられることを願っている。困ったことがあれば、いつでもまた相談に来てくれ。
