1. 導入:なぜ今、CEIL/FLOORの精度を疑う必要があるのか
メインフレーム開発において、数値計算はビジネスロジックの根幹です。特に金融計算やシミュレーションでは、小数点以下の端数処理に「CEIL(切り上げ)」や「FLOOR(切り下げ)」を多用します。しかし、PL/IやCOBOL等のレガシー環境における浮動小数点(HFP形式)計算では、内部表現の精度限界により、本来「1.0」であるべき値が「0.999999999…」と評価されることがあります。この微細な誤差が、意図せぬ切り上げ・切り下げを引き起こし、バグの温床となるのです。本稿では、この「偽の端数」問題を回避し、堅牢な計算ロジックを実装する方法を解説します。
2. 基礎知識:浮動小数点とHFP形式の限界
メインフレームで一般的に扱われるHFP(Hexadecimal Floating Point)は、16進数ベースの浮動小数点形式です。これらは非常に広範囲の数値を表現できますが、10進数との変換時に「基数変換誤差」が発生します。
例えば、CEIL関数は引数の値が整数よりわずかでも大きければ切り上げを行いますが、本来整数であるはずの計算結果が、精度不足により「整数+微小値」として保持されていると、CEIL関数はこれを「切り上げ対象」と判断してしまいます。これが現場でよく見られる「計算が1だけずれる」現象の正体です。
3. 実装/解決策:イプシロン(極小値)による補正
この問題を解決する最も実用的で標準的な手法は、計算結果に対して「微小なイプシロン値(許容誤差)」を事前に加減算してから関数に渡すことです。これにより、浮動小数点の計算結果が本来の整数値に対してわずかに下振れしていても、正しく判定させることが可能になります。
4. サンプルプログラム:PL/Iによる安全な端数処理の実装
以下は、浮動小数点の精度問題を考慮したPL/Iのコード例です。
/ 定数定義:精度誤差を吸収するための微小値(イプシロン) /
DCL EPSILON FLOAT BIN(53) INIT(1.0E-10);
DCL FLOAT_VAL FLOAT BIN(53);
DCL INT_RESULT FIXED BIN(31);
/
計算結果が「1.0」になるべきところで「0.9999999999」と
なってしまうケースを想定したサンプル
/
FLOAT_VAL = 0.999999999999;
/
そのままCEILを通すと「1」になることを期待するが、
もし値が「1.000000000001」だった場合に「2」に跳ね上がるリスクがある。
以下のようにイプシロンで補正を行うのが鉄則。
/
/ 切り上げの場合:わずかに減算してからCEILすることで、精度不足による過剰な切り上げを防ぐ /
INT_RESULT = CEIL(FLOAT_VAL – EPSILON);
/ 切り下げの場合:わずかに加算してからFLOORすることで、精度不足による過剰な切り下げを防ぐ /
INT_RESULT = FLOOR(FLOAT_VAL + EPSILON);
5. 応用・注意点:現場で陥りやすい罠
1. 固定小数点数への移行を検討する
可能であれば、ビジネスロジックには `FIXED DECIMAL`(パック10進数)を使用することを強く推奨します。浮動小数点を使う必要がない場面(金額計算など)でHFP形式を使うことは、現代のメインフレーム開発では避けるべき「技術的負債」です。
2. イプシロンの選定
イプシロンの値は、業務ロジックの許容誤差に合わせて調整してください。あまりに大きな値を設定すると、本来切り上げるべきケースまで無視してしまう可能性があります。
3. テストケースの網羅
境界値(整数値そのもの)および、演算結果が「整数付近」になるケースを必ずテストデータに含めてください。特に「0.99…」と「1.00…」の境目で関数がどう振る舞うかをエミュレータ上で検証することが重要です。

コメント