メインフレームからの脱却:PL/I `FIXED DECIMAL` と Java `BigDecimal` の「危うい関係」
長年、基幹システムの屋台骨を支えてきたPL/I。特に金融や公共のバッチ処理において、`FIXED DECIMAL(p, q)` は、金銭計算における「絶対的な正義」として君臨してきました。しかし、いざJavaへのマイグレーションとなると、この「絶対」が途端に足元をすくう罠へと変貌します。
今日は、メインフレームの現場で叩き上げられたエンジニアが、Javaリプレイスの最前線で直面する「精度の壁」について、深掘りしていきましょう。
—
なぜ「パック10進数」は最強なのか
PL/Iの `FIXED DECIMAL(p, q)` は、内部的にはパック10進数(Packed Decimal)として表現されます。これは、1バイトに2桁の数値を詰め込み、末尾に符号を置く形式です。
特筆すべきは、「10進数としての正確性」です。2進数の浮動小数点数(Binary Floating Point)とは異なり、0.1のような「2進数で循環小数になってしまう値」を、10進数として完全に保持できます。これが、基幹システムの会計計算において必須の条件なのです。
Javaリプレイスにおける「丸め」の落とし穴
Javaでこれを再現する場合、当然 `java.math.BigDecimal` を選択することになります。しかし、ここで多くのプロジェクトがハマるのが「デフォルトの挙動」です。
1. 丸めモードの不一致: PL/Iの算術演算は、桁あふれや精度変換時に特有の「切捨て(Truncation)」が発生しますが、Javaの `BigDecimal` はデフォルトで `HALF_UP`(四捨五入)や `UNNECESSARY`(例外発生)を要求します。
2. 演算結果の精度(Scale): PL/Iでは計算途中の精度もコンパイラが自動管理しますが、Javaでは明示的に `setScale()` を呼び出し、丸めモードを指定しなければなりません。これを怠ると、わずかな「1円の差」がバッチのトータルチェックで突き刺さります。
—
実践:PL/Iにおける精密な計算処理
現場でよく見る「計算とエラーハンドリング」の定石を見てみましょう。特に `ON-UNIT` を使ったオーバーフロー制御は、今のエンジニアも改めて見直すべき基本です。
1
/ ————————————————————- /
/ サンプル:FIXED DECIMALを用いた計算ロジック /
/ ————————————————————- /
CALC_PROC: PROCEDURE OPTIONS(MAIN);
/ 宣言:15桁、小数点以下2桁の固定小数点数 /
DCL AMOUNT_A FIXED DEC(15, 2) INIT(1000.50);
DCL AMOUNT_B FIXED DEC(15, 2) INIT(0.33);
DCL RESULT FIXED DEC(15, 2);
/ オーバーフロー発生時の制御:ON-UNIT /
ON FIXEDOVERFLOW BEGIN;
PUT SKIP LIST(‘警告:演算結果が桁あふれを起こしました’);
END;
/ 計算処理:PL/Iのコンパイラはここでの切り捨てを自動処理する /
/ ※Java移行時は、この結果に一致させる必要がある /
RESULT = AMOUNT_A AMOUNT_B;
PUT SKIP LIST(‘計算結果:’, RESULT);
END CALC_PROC;
—
マイグレーションを成功させるための「戦術」
リプレイスを成功させるためには、以下の3点を徹底してください。
1. 「再計算試験」の自動化:
メインフレーム上の旧システムで出力された計算結果のログと、Java上の計算結果を、1円単位で突き合わせるテストツールを作成してください。「なんとなく合っている」は、基幹システムでは通用しません。
2. 丸めモードの固定化:
プロジェクト全体で `RoundingMode` を統一してください。PL/Iの仕様を再現するなら、多くの場合 `RoundingMode.DOWN` (切り捨て) が適していますが、既存の業務ロジックがどう設計されているかを、ソースコードの `BUILTIN` 関数(`TRUNC` や `FLOOR`)から読み解く必要があります。
3. ON-UNITのJava化:
PL/Iの `ON FIXEDOVERFLOW` や `ON ZERODIVIDE` は、Javaでは `try-catch` ブロックへの変換となります。単に例外を握りつぶすのではなく、メインフレーム時代と同様の「異常終了ログ」を正確に吐き出す仕組みを構築してください。
最後に:仕様を「コードから読み解く」力
メインフレームのコードは時に古臭く見えるかもしれません。しかし、そこには「なぜその精度が必要だったか」という業務の知恵が凝縮されています。Javaという新しい言語へ移植する際、単なる「構文変換」に終始せず、その裏にある数値の挙動を深く理解してください。
もし現場で「計算が合わない」という壁にぶつかったら、まずはPL/Iの宣言にある `(p, q)` を紙に書き出し、計算の途中でどこで桁が落ちているのかをトレースすること。結局、最後は「基本」が一番の武器になります。
健闘を祈ります。また現場でお会いしましょう。
