1. 導入:なぜ「除算の精度」が重要なのか
メインフレームでのCOBOL等の事務計算において、算術演算の精度管理はシステムの信頼性に直結します。特に除算(割り算)を行う際、システム内部では「結果の小数点以下の桁数(スケールファクタ:q)」を可能な限り最大化しようとする挙動があります。この仕様を理解していないと、予期せぬ桁あふれ(FOFL:Fixed-point Overflow)を引き起こし、計算結果が異常値となるリスクがあります。本稿では、この挙動の仕組みと、現場で長年使われてきた「回避ハック」の正体を解説します。
2. 基礎知識:スケールファクタ(q)とは
メインフレームの固定小数点演算では、数値の宣言を「P(p,q)」のように指定します。
p(プレシジョン)は全体の桁数、q(スケールファクタ)は小数点以下の桁数です。
例えば、P(5,2)であれば「123.45」という数値を格納できます。除算において、被除数(割られる数)と除数(割る数)から結果を導き出す際、コンパイラは「精度を落とさないように」と、結果のqを自動的に最大化しようと試みます。これが、整数部の桁数を圧迫する原因となります。
3. 実装と解決策
例えば、15桁で小数点以下2桁の数値 A(15,2) を、整数 2桁の数値 B(2,0) で割る場合を考えます。
単純に `A / B` を行うと、システムは結果の精度を確保しようとして、必要以上に小数点以下の桁数を割り当て、結果として整数部が1桁しか残らないような事態を招くことがあります。大きな数値同士の計算では、これがあっという間にオーバーフローを引き起こします。
これを回避するために、古くからの技術者は計算式に「1.0」を掛けるという手法を用いてきました。これは、リテラル(定数)の精度を演算に介入させることで、コンパイラが自動決定する結果のスケールファクタを意図的に制御するテクニックです。
4. サンプルプログラム
以下のコード例は、計算の精度を意図的に制御する典型的なパターンです。
- — 精度制御のサンプルコード —
01 WS-VALUE-A PIC S9(13)V99. 15桁(整数13, 小数2)
01 WS-VALUE-B PIC S9(02). 2桁(整数2)
01 WS-RESULT PIC S9(13)V99. 計算結果格納用
- 1. 危険なパターン:
- コンパイラ任せになり、予期せぬFOFLが発生する可能性がある
DIVIDE WS-VALUE-A BY WS-VALUE-B GIVING WS-RESULT.
- 2. 回避ハックを用いたパターン:
- 1.0を掛けることで演算のスケールを調整し、精度を安定させる
COMPUTE WS-RESULT = (WS-VALUE-A 1.0) / WS-VALUE-B.
- 解説:
- 1.0 は固定小数点リテラルとして扱われ、このリテラルを介することで
- 中間結果のスケールファクタが固定され、整数部の桁落ちを防ぐ。
5. 応用・注意点:移行時の「意味不明な1.0」
レガシーシステムの移行や保守において、なぜか演算式の中に ` 1.0` や ` 1` が記述されているコードを見かけることがありますが、これは単なる無駄な記述ではありません。当時のプログラマーが「算術演算の内部精度」を制御するために施した、経験則に基づくハックです。
このコードを「不要な記述」と判断して削除してしまうと、本番環境で突然の数値オーバーフローが発生し、重大な障害につながる恐れがあります。移行時には、その演算がどの程度の精度を必要としているのかを定義書と照らし合わせ、単に削除するのではなく、明示的な型変換やCOMPUTE文による精度制御へ置き換えるのが安全なアプローチとなります。

コメント