【実務・中級編】FLOAT BINARY/DECIMALのIEEE 754準拠と精度 – PL/Iの基本構文とデータ制御実践ガイド

メインフレームの闇:浮動小数点演算の「誤差」と向き合う技術論

現場で長年バッチ改修を繰り返していると、必ず一度は頭を抱える問題がある。「なぜ、計算結果の最後の1桁が合わないのか?」という問いだ。

特に、PL/Iで`FLOAT BINARY`や`FLOAT DECIMAL`を扱う際、IEEE 754規格の挙動を理解していないと、大規模マイグレーションや再構築の現場で痛い目を見る。今日は、コンパイラの「親切心」が招く数値の罠と、それを回避するためのプラクティスについて語ろう。

1. なぜ「0.1」が正確に表現できないのか

我々が普段使う10進数と、CPUが処理する2進浮動小数点の間の「翻訳」こそが、誤差の根源だ。

`FLOAT BINARY`は2進数で数値を保持する。0.1という数値は、2進数では「0.0001100110011…」と循環小数になる。これを有限のビット数(単精度や倍精度)で切り詰めると、どうしても元の0.1とはわずかに異なる値になる。これが「丸め誤差」の正体だ。

特に、VSAMファイルやDB2から読み込んだデータを浮動小数点として保持し、それを比較演算子(`=` や `^=`)で判定する際、「等しいはずなのに等しくない」という現象が多発する。

2. 実践コード:誤差を考慮した比較術

実務では、単に `IF A = B THEN` と書いてはいけない。許容範囲(エプシロン)を設けた比較が鉄則だ。

1
TEST_CALC: PROC OPTIONS(MAIN);

/ 精度を担保するため、倍精度(FLOAT BINARY(53))を使用するのが定石 /
DCL VAL_A FLOAT BINARY(53) INIT(0.1E0);
DCL VAL_B FLOAT BINARY(53) INIT(0.0E0);
DCL DELTA FLOAT BINARY(53) INIT(1.0E-10); / 許容誤差範囲 /
DCL I FIXED BIN(31);

/ 0.1を10回足すという、誤差が累積しやすい典型的なループ /
DO I = 1 TO 10;
VAL_B = VAL_B + 0.1E0;
END;

/ 危険な比較:結果は通常「偽(FALSE)」になる /
IF VAL_A 10 = VAL_B THEN
PUT SKIP LIST(‘一致しました’);
ELSE
PUT SKIP LIST(‘一致しません:誤差が生じています’);

/ 安全な比較:差の絶対値が許容範囲内かを確認する /
IF ABS(VAL_A 10 – VAL_B) < DELTA THEN PUT SKIP LIST('許容範囲内で一致とみなします'); END TEST_CALC;

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

浮動小数点演算は、レコード入出力時にも注意が必要だ。特に`FIXED DECIMAL`(パック10進数)から`FLOAT`へ変換する際、桁落ちや精度変換が発生する。

もし計算中にオーバーフローやアンダーフローが発生した場合、`ON`ユニットで適切にトラップしなければ、ジョブは異常終了(ABEND)し、夜間バッチの復旧作業という悪夢を見ることになる。

1
/ 数値演算エラー時のハンドリング /
ON CONVERSION BEGIN;
PUT SKIP LIST(‘データ変換エラーが発生しました。入力データを確認してください。’);
/ ここでログ出力や終了処理を行う /
SIGNAL FINISH;
END;

ON OVERFLOW BEGIN;
PUT SKIP LIST(‘浮動小数点演算でオーバーフローを検知’);
END;

4. ベテランからのアドバイス:IEEE 754と付き合うための心得

1. 可能な限り `FIXED DECIMAL` を選べ
ビジネスロジック、特に金額計算においては `FLOAT` を使ってはいけない。`FIXED DEC(15,2)` のような固定小数点形式は、10進数として正確に管理される。マイグレーション案件で「性能が出るから」と安易に `FLOAT` を採用すると、後で検算が合わずに泣くことになる。
2. `FLOAT` を使うなら `BUILTIN` 関数を信じろ
`ROUND` や `TRUNC` などの組み込み関数は、ハードウェアの特性を考慮した実装になっている。自前でビット演算などを弄るような真似は避け、標準ライブラリに任せるのが、保守コストを下げる唯一の道だ。
3. 比較演算には「EPSILON」を定数化せよ
プロジェクト全体で「この値以下の差は無視する」という閾値を定義し、それを共通のインクルード(`%INCLUDE`)で管理せよ。

最後に

PL/Iは古い言語と言われることもあるが、その言語仕様の堅牢さと、コンパイラが提供する強力な数値制御機能は、未だにメインフレームの基幹業務を支える最強の武器だ。

浮動小数点の誤差は「バグ」ではなく「性質」だ。この性質を正しく理解し、制御下に置くことこそが、一流のメインフレーム・アーキテクトへの第一歩である。次の改修時、`FLOAT` 変数を見かけたら、この記事のことを思い出してほしい。コードの裏側にある「論理」を正しく設計すること。それが、我々の仕事の価値なんだ。

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