【現場の極意】FIXED BINARY(15) vs (31) ―― メインフレームの演算効率と「落とし穴」を徹底解剖する
若手から「計算フィールドの定義、とりあえず `FIXED BIN` にしてますが、(15)と(31)って何か違いがあるんですか?」と聞かれることがよくある。
結論から言えば、「単なる桁数の違い」と思って実装していると、ある日突然、本番環境で「SOC7」ならぬ「計算結果の予期せぬ切り捨て」や、性能劣化という名のしっぺ返しを食らうことになる。
今日は、z/OSのCPUアーキテクチャまで踏み込み、我々メインフレームエンジニアが知っておくべき「整数演算の正体」について語ろうと思う。
—
1. 内部表現のリアル:ハーフワードとフルワード
PL/Iにおいて `FIXED BIN(15)` は2バイト(ハーフワード)、`FIXED BIN(31)` は4バイト(フルワード)のメモリを占有する。
- FIXED BIN(15): -32,768 ~ 32,767
- FIXED BIN(31): -2,147,483,648 ~ 2,147,483,647
ここで重要なのは、System zのCPU命令セットだ。現代のメインフレームにおいて、多くの演算はフルワード(32ビット)単位で行われるのが効率的である。ハーフワードのデータをロードする際、CPUはそれをフルワードに拡張(符号拡張)してレジスタに乗せる。つまり、微々たるものだが、(15)を多用するとロード時のサイクルがわずかに増えるという現実がある。
2. なぜ(15)を使うのか? それは「VSAM」のためだ
では、すべて(31)にすればいいのかと言えば、そうではない。最大の理由はレコードレイアウト(DSECT/COPYBOOK)との整合性だ。
COBOLの `PIC S9(4) COMP` とデータ交換を行う場合、PL/I側で `FIXED BIN(15)` を指定しなければ、物理的なオフセットがずれてしまう。レガシーなDB2テーブルやVSAMファイルは、この「サイズ」に対して極めてシビアだ。
3. 実践:安全なコーディングとONユニットによる制御
では、オーバーフロー対策を含めた実践的なコードを見てみよう。PL/Iの魅力は、`ON-UNIT` による例外処理の柔軟性にある。
1
/ メインプログラムの構成 /
SAMPLE_BATCH: PROCEDURE OPTIONS(MAIN);
/ フィールド定義 /
DCL W_COUNT_SHORT FIXED BIN(15) INIT(0); / ハーフワード:カウンタ等 /
DCL W_COUNT_LONG FIXED BIN(31) INIT(0); / フルワード:集計用 /
/ オーバーフロー時の制御(重要!) /
ON FIXEDOVERFLOW
BEGIN;
PUT SKIP LIST(‘警告: 計算結果が範囲を超えました。値を補正します。’);
W_COUNT_SHORT = 32767; / 異常時の安全な退避値 /
END;
/ 計算処理の例 /
W_COUNT_SHORT = W_COUNT_SHORT + 1;
/ VSAMアクセスを想定したデータ操作 /
/ BUILTIN関数による型変換と精度の明示 /
IF BINARYVALUE(W_COUNT_SHORT) > 30000 THEN DO;
/ 長期的な集計は必ず(31)で行うこと /
W_COUNT_LONG = W_COUNT_LONG + W_COUNT_SHORT;
END;
RETURN;
END SAMPLE_BATCH;
ここが現場の勘所
1. 演算の連鎖: `FIXED BIN(15)` 同士で演算を行うと、PL/Iコンパイラは一時的にその結果をフルワードとして扱う。この「中間結果」を再度 `(15)` に戻す際に切り捨てが発生する。「小さければいい」という考えは捨てろ。 演算の途中で範囲を超える可能性があるなら、必ず `(31)` を噛ませるのが鉄則だ。
2. VSAMアクセス: VSAMファイルから読み込んだデータをそのまま `(15)` で保持し、集計ループの中で加算し続けるような設計は非常に危険だ。読み込みは `(15)`、処理は `(31)`、書き込みは `(15)` へキャスト、という三段構えを徹底してほしい。
3. パフォーマンス: 現代のz/Architectureにおいて、計算回数が数百万件を超えるバッチでない限り、(15)と(31)の演算性能差でシステムが止まることはまずない。それよりも、「オーバーフローでバッチが異常終了すること」のコストの方が遥かに高い。
結論:迷ったら(31)に倒せ
新人の頃、「メモリを節約しろ」と教えられたかもしれない。だが、今のメインフレームにおけるメモリ資源とCPU性能を考えれば、「安全性(オーバーフローしない)」と「コードの可読性」を優先すべきだ。
特別な理由がない限り、カウンタや集計フィールドは `FIXED BIN(31)` を標準とせよ。そして、外部インターフェース(ファイル定義)と合わせる必要がある時だけ、`(15)` を慎重に選択する。
この「意識的な使い分け」こそが、大規模マイグレーションや複雑なバッチ改修を生き抜くための、ベテランの作法だ。さて、次のコンパイルを通す前に、もう一度定義を見直してみるといい。おかしな場所が見つかるはずだ。
