【実務・中級編】FIXED DECIMAL(p,q)のパック10進数形式と演算 – PL/Iの基本構文とデータ制御実践ガイド

メインフレームの心臓部を守る:FIXED DECIMAL(p,q)とCOMP-3の深淵

若手エンジニアからよく相談されるのが、「なぜPL/Iの計算結果で数値が化けるのか?」あるいは「VSAMファイルに書き出したデータがダンプで見ると奇妙な値になっている」という悩みだ。

金融機関や公共システムの基幹バッチで、`FIXED DECIMAL(15, 2)`のような型を見かけない日はない。これは単なる型宣言ではなく、我々が守り抜いてきた「1円の誤差も許さない」というエンジニアの矜持そのものだ。今日は、このパック10進数(COMP-3)の挙動と、現場で死なないための演算術について語ろう。

1. FIXED DECIMALの正体:パック10進数の物理構造

PL/Iで `DCL AMT FIXED DECIMAL(5, 2);` と定義した場合、内部ではどうなっているか。これは「パック10進数形式」でメモリに配置される。

  • 物理構造: 1バイトに2桁の数値を詰め込み、末尾のニブル(4ビット)に符号(正なら `C`、負なら `D`)を格納する。
  • なぜ使うのか: 二進数浮動小数点(BINARY FLOAT)で発生する「0.1の誤差」を排除するためだ。貨幣計算においては、誤差は致命的なシステム障害に直結する。

2. 演算時の自動調整と「桁落ち」の恐怖

PL/Iのコンパイラは優秀だ。異なる精度の `FIXED DECIMAL` 同士で演算を行う際、小数点位置を自動的に揃えてくれる。しかし、この「親切心」が時に罠となる。

例えば、`(10, 2) (10, 2)` を行うと、中間結果は `(21, 4)` に引き上げられる。この挙動を知らずに、受け側の変数の精度が足りないと、コンパイラは警告を出さずに上位桁を切り捨てる(もしくは桁あふれを起こす)ことがある。

現場の鉄則: 中間演算の結果は、必ず計算機専用のワーク変数で受けろ。

1
/ ———————————————————– /
/ 計算ワーク用変数の定義例 /
/ 物理的な精度の限界を意識し、中間計算は余裕を持たせる /
/ ———————————————————– /
DCL WK_CALC_AMT FIXED DECIMAL(15, 4) INIT(0);
DCL AMT_A FIXED DECIMAL(9, 2) INIT(100.50);
DCL AMT_B FIXED DECIMAL(9, 2) INIT(200.75);

/ 演算実行:自動的に小数点位置が調整される /
WK_CALC_AMT = AMT_A AMT_B;

/ 結果を丸める際は、必ずBUILTIN関数を活用する /
/ 単なる代入ではなく、ROUND関数で精度の制御を明示的に行う /
DCL FINAL_AMT FIXED DECIMAL(9, 2);
FINAL_AMT = ROUND(WK_CALC_AMT, 2);

3. VSAM入出力とONユニットの制御フロー

大規模改修で最も怖いのが、VSAMのレコードを読み込み、フィールドを再定義して演算を行う際の「型不一致」だ。特に `ON CONVERSION` を設定していないと、不正なパックデータが読み込まれた瞬間にアベンド(S0C7)が待っている。

現場のベテランは、必ず変換エラーをトラップする安全装置を仕込んでおくものだ。

1
MAIN_PROC: PROCEDURE OPTIONS(MAIN);

/ 変換エラーを捕捉するONユニットを定義 /
ON CONVERSION BEGIN;
PUT SKIP LIST (‘データ変換エラーが発生しました。入力データを確認してください。’);
SIGNAL FINISH;
END;

/ VSAMレコードの構造体定義 /
DCL 1 VSAM_REC,
5 KEY_ID CHAR(8),
5 AMT_RAW FIXED DECIMAL(7, 2); / ここにCOMP-3データが来る /

/ 読み込み処理(イメージ) /
READ FILE(INPUT_FILE) INTO(VSAM_REC);

/ 演算処理 /
IF AMT_RAW > 0 THEN
DO;
/ 何らかの計算処理 /
END;

END MAIN_PROC;

4. ベテランからのアドバイス:保守で生き残るために

1. 暗黙の型変換を信じるな: 異なる精度の変数を混ぜる演算では、必ず `FIXED DECIMAL` の精度を明示的に意識しろ。`FIXED BINARY` と混ぜると、コンパイラは二進数演算へ引きずり込もうとする。それが原因で計算結果が数円ずれる事故を、私は過去に何度も見てきた。
2. ダンプ解析は「16進数」で読め: 画面上の値が正しいか疑わしい時は、ストレージダンプを16進数で追え。`0C` や `0D` が末尾に見えれば、それは紛れもなく正しいパック10進数だ。
3. BUILTIN関数は正義: `ADD(x, y, p, q)` や `MULTIPLY(x, y, p, q)` を使えば、演算結果の精度を意図的に固定できる。面倒がらずにこれらを使え。

メインフレームのコードは、先人たちが何十年もかけて積み上げた知恵の結晶だ。新しい言語のような「適当さ」は許されないが、その分、ルールを守ればこれほど堅牢で信頼できるシステムはない。

もし改修中に壁にぶつかったら、まずは `DCL` 宣言に戻れ。データ型こそが、システムが何を考えているかを知る唯一の言語なのだから。

タイトルとURLをコピーしました