1. 導入:なぜこの「型混合」が危険なのか
メインフレームのPL/I開発において、MAX関数やMIN関数は非常に便利です。しかし、異なる属性(FIXED DECIMAL、FIXED BINARY、FLOATなど)を一つの関数に投げ込むと、PL/Iは気を利かせて内部的に「共通の型」へ変換を行います。この「暗黙の型変換」こそが、予期せぬ精度低下や計算誤差を招く主犯です。本稿では、この挙動を正しく理解し、安全なコードを書くためのTipsを解説します。
2. 基礎知識:PL/Iの「昇格」ルール
PL/Iでは、算術データ型の優先順位が決まっています。異なる型が混在する場合、基本的に以下の順で「精度の高い型」へ自動変換されます。
FIXED BINARY → FIXED DECIMAL → FLOAT
特に注意すべきは、FLOATへの変換です。FLOATは広範囲を扱えますが、内部的には近似値として保持されるため、高精度な固定小数点数(DECIMAL(15, 5)など)をMAX関数に渡すと、意図せずFLOATに変換され、末尾の桁が切り捨てられるといった現象が発生します。
3. 実装/解決策:明示的な型合わせ
この問題を回避する鉄則は「比較対象の型を揃えること」です。暗黙の変換に頼るのではなく、比較する前にすべて同じ精度・型にキャスト(変換)することで、副作用を完全にコントロールできます。
4. サンプルプログラム
以下は、属性の異なる変数を比較する際の安全な実装例です。
/ サンプル:型を明示的に揃えてMAXを求める /
DECLARE
INT_VAL FIXED BIN(31) INITIAL(100),
DEC_VAL FIXED DEC(7,2) INITIAL(99.99),
FLOAT_VAL FLOAT BIN(21) INITIAL(105.5),
RESULT FIXED DEC(7,2);
/ 悪い例:MAX(INT_VAL, FLOAT_VAL) と書くとFLOATに引きずられ精度が落ちる可能性がある /
/ 良い例:全てをFIXED DEC(7,2)に揃えてから比較を行う /
RESULT = MAX(
DEC(INT_VAL, 7, 2), / 明示的にFIXED DECへ変換 /
DEC_VAL,
DEC(FLOAT_VAL, 7, 2) / 浮動小数点も精度を固定して変換 /
);
PUT SKIP LIST(‘最大値は:’, RESULT);
5. 応用・注意点:オープン系への移行を見据えて
現代のシステム移行において、このPL/Iの「柔軟すぎる仕様」は大きなハードルになります。JavaのCollections.max()やC#のLINQなどは、ジェネリクスにより「型の一致」を厳格に求めます。
PL/IからJava等へロジックを移植する際、元のコードで「型が混在している箇所」は、すべて明示的なキャストが記述されているか確認してください。もしPL/I側で暗黙の変換に依存したまま移植すると、境界値で結果がズレる致命的なバグになります。現場では「計算の前に型を合わせる」という意識を、ソースコードの可読性を高めるための「設計」として定着させましょう。

コメント