【PL/I学習|豆知識】算術条件の優先順位とカッコの評価 ~PL/Iで陥りがちなオーバーフロー回避術~

はじめに

メインフレームの世界では、数値計算の正確さがビジネスの根幹を支えています。PL/Iで算術式を扱う際、演算の「優先順位」と「カッコ」の使い方が、意図しない結果やオーバーフローを引き起こす原因となることがあります。今回は、PL/Iにおける算術条件の優先順位とカッコによる評価順序の変更が、どのように数値計算に影響を与えるのか、そしてオーバーフローを回避するための具体的なテクニックについて解説します。

PL/Iの算術演算子の優先順位

PL/Iでは、算術演算子に以下のような優先順位が定められています。

1. べき乗 ()符号反転 (+): 最も優先度が高いです。
2. 乗算 ()除算 (/): 次に優先されます。
3. 加算 (+)減算 (-): 最も優先度が低いです。

この優先順位は、プログラミング言語一般に共通する部分も多いですが、PL/I特有の「中間精度ルール」が絡んでくる点が重要です。

カッコがもたらす「中間精度の再評価」

PL/Iでは、カッコ `()` を使用することで、演算の評価順序を強制的に変更できます。しかし、単純に評価順序が変わるだけでなく、カッコで囲まれた部分(サブ・エクスペリション)は、それぞれ独立した「中間精度」で再評価されるという特徴があります。

この「中間精度の再評価」が、オーバーフローの発生有無に大きく影響します。例えば、大きな数同士の乗算を行った後、それを小さな数で割る場合を考えてみましょう。

  • 例1: (A B) / C

まず `A B` が計算され、その結果を `C` で割ります。もし `A B` の計算結果が、変数の定義精度を超えてしまうほど大きくなると、ここでオーバーフローが発生する可能性があります。

  • 例2: A (B / C)

この場合、まず `B / C` が計算されます。その結果を `A` に掛け合わせます。`B / C` の段階で結果が小さくなる可能性があり、その後の `A` との乗算でオーバーフローを起こしにくくなることがあります。

このように、カッコの使い方一つで、計算途中で発生する中間結果の大きさが変わり、結果としてオーバーフローの有無が変わってくるのです。

サンプルプログラム:オーバーフロー回避のデモンストレーション

ここでは、意図的にオーバーフローを起こしやすい状況を想定し、カッコの有無による違いを示すサンプルプログラムを示します。

1
/

  • このプログラムは、PL/Iにおける算術演算の優先順位と
  • カッコの使用がオーバーフローに与える影響を示すためのサンプルです。

/
DCL A FIXED DECIMAL(15,0) INIT(1000000000); / 大きな整数 /
DCL B FIXED DECIMAL(15,0) INIT(1000000000); / 大きな整数 /
DCL C FIXED DECIMAL(5,0) INIT(2); / 小さな整数 /
DCL RESULT1 FIXED DECIMAL(15,0); / 結果格納用変数1 /
DCL RESULT2 FIXED DECIMAL(15,0); / 結果格納用変数2 /

/

  • ケース1: (A B) / C
  • AとBの乗算でオーバーフローが発生する可能性が高い

/
ON OVERFLOW BEGIN
PUT SKIP LIST(‘オーバーフロー発生! (A B) / C’);
/ エラー処理や代替処理をここに追加できます /
STOP; / プログラムを停止 /
END;

RESULT1 = (A B) / C;
PUT SKIP LIST(‘ケース1 結果: ‘, RESULT1);

/

  • ケース2: A (B / C)
  • B / C を先に計算することで、中間結果が小さくなり、
  • オーバーフローを回避できる可能性が高まる

/
/ ON OVERFLOW は必要に応じて再設定するか、このセクションでオーバーフローが発生しないと仮定 /
RESULT2 = A (B / C);
PUT SKIP LIST(‘ケース2 結果: ‘, RESULT2);

END;

このプログラムを実行すると、`A B` の計算でPL/Iの精度限界を超えてしまう場合、ケース1ではオーバーフローが発生し、`ON OVERFLOW` のブロックが実行されます。一方、ケース2では `B / C` の結果が小さくなるため、オーバーフローを回避できる可能性が高まります。

現場で役立つ応用・注意点

1. 中間結果の精度を意識する

PL/Iの「中間精度ルール」は、演算の結合順序によって個別に適用されます。単一の巨大な式にまとめると、PL/I特有の中間結果の切り捨てが発生し、意図しない計算結果になることがあります。
もし、最終的な結果が許容範囲内であっても、計算途中でオーバーフローを起こしそうな場合は、意図的にステップを分け、カッコを使って中間結果の精度をコントロールすることが重要です。

2. データ型の定義に注意する

使用する変数のデータ型(`FIXED DECIMAL`, `FLOAT BINARY` など)とその精度(桁数や小数点以下の桁数)は、オーバーフローに直結します。計算される可能性のある最大値・最小値を考慮し、余裕を持った精度で定義することが基本です。特に、大きな数同士の乗算や、小さな数での除算を繰り返すような処理では注意が必要です。

3. `ON OVERFLOW` の活用

PL/Iには `OVERFLOW` 例外処理があります。これを適切に設定することで、オーバーフロー発生時にプログラムを安全に停止させたり、代替処理を実行させたりすることができます。予期せぬオーバーフローによるデータ破損を防ぐために、重要な数値計算ルーチンでは `ON OVERFLOW` の設定を検討しましょう。

4. 移行時の注意点

近年、COBOLなど他の言語への移行(マイグレーション)が行われることがありますが、PL/Iのこの「中間精度ルール」は移行先の言語には存在しないことがほとんどです。移行先の言語で同じように単一の式として記述すると、PL/Iではオーバーフローしなかった計算が、移行先ではオーバーフローしたり、逆にPL/Iではオーバーフローしていた計算が移行先では問題なく実行されたりするなど、挙動が変わる可能性があります。移行時には、PL/Iの計算ロジックを詳細に分析し、必要に応じて計算ステップを分割するなどの対応が必要になります。

まとめ

PL/Iにおける算術条件の評価順序とカッコの使い方は、単に計算順序を変えるだけでなく、中間結果の精度に影響を与え、オーバーフローの発生を左右します。これらの特性を理解し、適切なカッコの使用やデータ型の定義、そして例外処理を組み合わせることで、正確で安全な数値計算を実現することができます。特に、長年稼働している基幹システムでは、これらの細かい挙動が信頼性に大きく関わってきますので、ぜひ日々の開発や保守に役立ててください。

コメント

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