浮動小数点の悪魔は細部に宿る:PL/IにおけるIEEE 754とIBM形式の深淵
メインフレームの世界に長くいると、「計算結果が0.0000000000001ずれる」という、一見些細だが致命的なバグに何度も出くわす。特に、長年使い古された勘定系バッチがオープン系へマイグレーションされる際や、コンパイラオプションを安易に切り替えた時に、この「浮動小数点の亡霊」が顔を出す。
今日は、PL/Iにおける `FLOAT BINARY` と `FLOAT DECIMAL`、そして避けては通れない「IBM形式」と「IEEE 754」の対立について、現場の視点から掘り下げてみよう。
—
1. なぜ「形式」が重要なのか?
我々が普段メインフレームで扱っている浮動小数点は、歴史的にIBM 16進浮動小数点形式(Hexadecimal Floating Point: HFP)が標準だった。しかし、現代のプロセッサ(z/Architecture)は、業界標準であるIEEE 754形式(Binary Floating Point: BFP)をネイティブでサポートしている。
ここで問題になるのが、以下の2点だ。
- 基数の違い: HFPは16進数ベースだが、IEEE 754は2進数ベース。これにより、同じ小数を表現しても、丸め誤差の出る桁や挙動が微妙に異なる。
- コンパイラオプションの罠: `FLOAT(HEX)` か `FLOAT(IEEE)` か。これを理解せずにコンパイルすると、再コンパイルしただけで計算結果の最終桁が変わり、突合エラーで深夜の呼び出しを食らうことになる。
—
2. 実践:精度の劣化を防ぐコードの書き方
浮動小数点の精度劣化を最小限に抑えるには、ハードウェアの特性を理解したコーディングが不可欠だ。以下に、精度の比較と `BUILTIN` 関数の適切な使い方を示すサンプルを記す。
1
/ PACKAGEを用いたモジュール構造の例 /
PRECISION_TEST: PACKAGE EXPORTS(CALC_MODULE);
CALC_MODULE: PROCEDURE OPTIONS(MAIN);
/ 宣言部:DECIMAL(15)は固定小数点として精度の担保に必須 /
DCL VALUE_A FLOAT BINARY(53) INIT(0.1E0); / IEEE 754倍精度相当 /
DCL VALUE_B FLOAT DECIMAL(16) INIT(0.1); / 精度を意識した記述 /
DCL RESULT FLOAT BINARY(53);
/ VSAMやファイル入出力での変換時、特に注意が必要 /
ON ENDFILE(SYSIN) BEGIN;
PUT SKIP LIST(‘データ処理終了’);
END;
/
- 浮動小数点の比較は絶対に行ってはならない。
- 必ず差分が許容範囲内かを確認する「エプシロン比較」を行う。
/
IF ABS(VALUE_A – 0.1) < 1E-9 THEN
PUT SKIP LIST('精度範囲内での一致と判定');
ELSE
PUT SKIP LIST('計算誤差が発生しています');
/
- BUILTIN関数の活用:
- ROUND関数は丸め位置を明示すること。デフォルトに頼るな。
/
RESULT = ROUND(VALUE_A 3.0, 2);
PUT SKIP EDIT(‘結果:’, RESULT)(A, F(10, 2));
END CALC_MODULE;
—
3. 現場で陥る「罠」と対策
① コンパイルオプションの不一致
既存のレガシーコードを最新のz/OS環境に持ち込む際、コンパイラオプションのデフォルトが変わっていることがある。マイグレーション時は、必ず `FLOAT(HEX)` が指定されているか、あるいは `FLOAT(IEEE)` への切り替えによる影響度調査(回帰テストの差異分析)を徹底してほしい。
② レコード入出力でのバイナリ変換
VSAMや順次ファイルに `FLOAT` 型を書き出す際、データ属性が一致していないと、読み込み時にビットパターンが解釈できず、異常な数値に化ける。特に外部システムと連携する場合、`IEEE 754` への統一が求められるケースが増えている。
③ ONユニットによる例外制御
浮動小数点のオーバーフローやアンダーフローは、計算途中にサイレントに発生する。`ON OVERFLOW` を適切に配置し、異常値を検知した瞬間にログを吐き出させ、処理を中断させる設計にしておくのが「賢い」システムだ。
—
最後に:アーキテクトからの助言
「PL/Iは古い」と揶揄する若手もいるが、これほど厳密に数値精度を制御できる言語は他にない。浮動小数点の扱いに迷ったら、まずは `FLOAT BINARY(53)` を使い、計算過程での丸めを最小限に抑えること。そして、どうしても10進数としての正確さ(金銭計算など)が必要なら、`FLOAT` ではなく `FIXED DECIMAL` に逃げる勇気を持つことだ。
技術は変わるが、数値が持つ厳格さは変わらない。皆さんのバッチ処理が、今日も正確に動くことを祈っている。もし計算誤差で夜中に呼び出されたら、まずはその演算が `HEX` なのか `IEEE` なのかを確認することから始めてくれ。それが、ベテランの最初の仕事だ。
