深淵なるPL/Iの世界:FIXED BINARY(p,q)の精度がシステム安定性に与える衝撃
IBMメインフレームの心臓部で稼働するPL/I。JavaやC#のモダンな言語に慣れたアーキテクトから見れば、「なぜ今さら固定小数点数なのか」と問われることもあるでしょう。しかし、基幹システムのマイグレーションにおいて、この`FIXED BINARY(p,q)`の挙動を読み違えることは、即座にS0C7アベンドや、最悪の場合は「なぜか計算結果が数円合わない」という、調査に数週間を要する悪夢のデータ不整合へと直結します。
今日は、メモリの極致と演算精度という、地味ながら極めて重要な領域にメスを入れます。
—
1. FIXED BINARYの内部構造:2バイトか4バイトか、それが問題だ
PL/Iの`FIXED BINARY(p, q)`は、単なる数値型ではありません。コンパイラは`p`(精度)の値を見て、その変数を2バイト(HALFWORD)にするか、4バイト(FULLWORD)にするかを決定します。
- pが1~15の場合: 2バイト(HALFWORD)として扱われます。
- pが16~31の場合: 4バイト(FULLWORD)として扱われます。
ここで注意すべきは、`q`(スケール)が及ぼす影響です。`q`は単なる小数点位置の指定であり、メモリサイズ自体には直接寄与しません。しかし、演算時にこの「2バイトか4バイトか」という境界線をまたぐ際、コンパイラは内部的に一時領域(Temporary)を生成します。
/i
DCL A FIXED BIN(15, 0); / 2バイト:-32,768 ~ 32,767 /
DCL B FIXED BIN(31, 0); / 4バイト:約±21億 /
/ ここでAにBを代入すると、コンパイラは暗黙的な変換を行う /
A = B;
アーキテクトの視点:
この代入時、もし`B`が32,767を超えていれば、実行時に`FIXEDOVERFLOW`(FOFL)が発生します。レガシー移行の際、移行先(Javaの`int`等)ではオーバーフローしない値が、PL/Iの`FIXED BIN(15)`の制約で突然アベンドするケースは後を絶ちません。ダンプ解析を行う際、`CEE3611I`等のメッセージが出たら、まずはこの境界値チェックを疑ってください。
—
2. コンパイラオプションと最適化の罠
皆さんが普段使っている`OPTIMIZE(2)`や`OPTIMIZE(3)`のオプションは、コードの実行速度を劇的に向上させますが、同時に「浮動小数点的な振る舞い」を誘発することもあります。
特に注意が必要なのが、`LIMITS(FIXEDBIN(p,q))`オプションです。マイグレーション時に、既存のソースコードを触らずにコンパイラレベルで精度を拡張しようとするのは、自殺行為です。既存の`FIXED BIN(15)`で設計されたロジックに、突如として大きな値が流れ込むと、CICSオンライン処理において予期せぬトランザクションアベンドを引き起こすからです。
—
3. ポインタ操作と動的メモリの深淵
基幹システムでは、複雑なレコードレイアウトを扱うためにポインタ(`BASED`変数)を多用します。ここで`FIXED BIN`を扱う際、アライメント(境界調整)が狂うと、ハードウェア例外が発生します。
/i
DCL PTR_DATA POINTER;
DCL 1 MY_REC BASED(PTR_DATA),
2 FIELD_A FIXED BIN(31), / 4バイトアライメントが必要 /
2 FIELD_B FIXED BIN(15); / 2バイトアライメント /
/ ポインタを動的に割り当てる際、必ずアライメントを意識せよ /
ALLOCATE MY_REC;
もし`PTR_DATA`を奇数アドレスに向けてしまった場合、`FIELD_A`へのアクセスで`S0C6`(Specification Exception)が飛んできます。Javaへの移行において、この「メモリレイアウトとアライメント」の概念をどう抽象化するか。これが、移行設計の成否を分ける境界線となります。
—
4. 現場の知見:パックデシマルとの混在による悲劇
`FIXED BIN`と`FIXED DEC`(パックデシマル)を混在させて演算すると、コンパイラは高コストな変換ルーチンを挿入します。
- パックデシマルの符号反転バグ:
古いシステムからマイグレーションする際、最も恐ろしいのは、EBCDICからASCIIへ移行する過程でパックデシマルの符号(X’C’やX’D’)が正しく変換されず、演算結果が反転するケースです。`FIXED BIN`へキャストする前に、必ず符号の正規化を行ってください。
/i
/ パックデシマルからFIXED BINへの変換例 /
DCL P_DEC FIXED DEC(5,0);
DCL B_BIN FIXED BIN(31);
/ 符号の異常がないか、必ずチェックしてから計算へ /
IF P_DEC < 0 THEN B_BIN = -1 ABS(P_DEC);
ELSE B_BIN = P_DEC;
---
結びに:レガシーを「言語」として捉える
PL/Iのコードは、単なる命令列ではありません。それは、数十年間のビジネスロジックが蓄積された「結晶」です。`FIXED BIN(p,q)`のわずか2バイトの差に、当時のプログラマが込めたメモリ節約の意図や、汎用機の限界に挑んだ知恵が隠されています。
マイグレーションを担当する皆さんへ。ツールによる自動変換だけに頼らず、コンパイラが出力するリスト(`LIST`オプションで出力されるコード展開)を読み解いてください。機械が解釈したロジックの裏側にある「意図」を理解できた時、初めて皆さんは真のシステムアーキテクトになれるはずです。
次回のブログでは、`CICS`環境下における`STORAGE`の解放漏れと、それによる`SOS`(Short On Storage)の深層調査についてお話しします。現場からは以上です。
