【実務・中級編】PRECISION関数の引数と戻り値の仕様 – PL/Iの基本構文とデータ制御実践ガイド

やあ。今日も今日とて、夜間バッチのABEND(異常終了)解析に追われていないか?
レガシーシステムの保全や、オープン系へのマイグレーション検証で最も頭を悩ませる問題の一つが、この「数値データの精度とオーバーフロー」だ。

特にPL/Iの `FIXED DECIMAL` や `FIXED BINARY` を扱う際、`PRECISION`(プレシジョン)関数を軽視したコードは、時限爆弾を抱えているようなものだ。本番稼働して何年も経った月末処理で、ある日突然 `S0C7` や `SIZE` 条件によるABENDを引き起こす。そんな現場の修羅場を、私は何度もくぐり抜けてきた。

今回は、PL/Iにおける `PRECISION` 関数の引数と戻り値の仕様、そして切り捨て・丸め処理、さらには恐ろしい `ON` ユニットの挙動について、実務で即役に立つノウハウを叩き込んでいこう。

—

1. 現場のエンジニアが陥る「プレシジョン」の罠

PL/Iの数値演算は、コンパイラが暗黙的に中間結果の精度を決定するため、一見するとプログラマは細かなビット数や桁数を気にしなくてよいように思える。だが、ここに大きな落とし穴がある。

「計算結果を特定のデータ構造(例えば、3桁の整数と2桁の小数を持つフィールド)に格納したい」あるいは「外部ファイルの旧フォーマットに合わせて桁数を強制的に調整したい」という時、適当な代入を行っていると、予期せぬデータ欠損や致命的なオーバーフローを招く。

ここで登場するのが `PRECISION` ビルトイン関数 だ。

`PRECISION` 関数の基本構文

1
DCL RESULT_VAL FIXED DEC(7, 2);
RESULT_VAL = PRECISION(EXPR, 5, 2);

  • 第1引数 (`EXPR`): 対象となる数値式。
  • 第2引数 (`PRECISION`): 戻り値の「全体の桁数(プレシジョン)」。
  • 第3引数 (`SCALE`): 戻り値の「小数部の桁数(スケール)」。※省略可能だが、固定小数点では極めて重要。

一見シンプルだが、この関数が返す「戻り値の属性」と、それに伴う切り捨てのルール、そしてオーバーフロー検知のタイミングを正確に理解しているエンジニアは、ベテランの中でもそう多くはない。

—

2. 切り捨て・丸め処理と「見えないデータロジック」

`PRECISION` 関数で指定した桁数が、元の値の桁数より小さい場合、はみ出た部分は容赦なく切り捨て(Truncation)られる。ここで重要なのは、四捨五入ではなく「切り捨て(切り詰め)」である点だ。

例えば、`FIXED DEC(5, 4)` の値 `1.2345` を `PRECISION(VAL, 3, 2)` で `FIXED DEC(3, 2)` に縮めようとすると、結果は `1.23` になる。
もし四捨五入が必要な場合は、`PRECISION` 単体ではなく、`ROUND` 関数を併用するか、あらかじめ算術的な丸め処理を入れる必要がある。この仕様を見落として金融系の単価計算などを実装すると、端数処理の不整合で監査に引っかかる大惨事になるので注意してほしい。

そして最も恐ろしいのは、整数部が入り切らない場合の「オーバーフロー(桁あふれ)」だ。

—

3. ON条件(SIZE / FIXEDOVERFLOW)の発火タイミング

指定したプレシジョン(特に整数部)を超える値が無理やり押し込められたとき、PL/Iは実行時エラーを発生させる。ここで登場するのがお馴染みの `ON` ユニットだ。

  • `SIZE` 条件: 変数への代入やデータ変換時に、有効桁数(特に整数部)が失われる場合に発火する。
  • `FIXEDOVERFLOW` (FOFL) 条件: 固定小数点演算の結果が、ハードウェアの表現限界(通常は `FIXED BIN(31)` または `FIXED DEC(15)`)を超えた場合に発火する。

実務上、VSAMファイルや固定長レコード(レコード入出力)からデータを読み込み、自前の構造体にマッピングする瞬間や、`PRECISION` 関数で意図的に桁数を削った代入を行う瞬間に、この `SIZE` 条件がトリガーされることが多い。

もし `ON SIZE` を捕捉するコードを記述していない場合、メインフレームは容認しがたい `IBM0265S SIZE CONDITION` などのメッセージを残して異常終了する。

—

4. 実践:PL/Iコード例による挙動の確認

百聞は一見にしかずだ。実際のメインフレーム開発を想定したバッチプログラムの骨組みを見てみよう。ここでは、VSAMマスターファイルから読み込んだ数値を安全に加工し、`PRECISION` 関数を適用するロジックを組んでいる。

1
;

  • MODULE NAME: PREC01P ;
  • DESCRIPON : PRECISION関数およびSIZE条件の挙動確認サンプル ;

;
PREC01P: PROC OPTIONS(MAIN);

/ — データ定義 — /
DCL IN_RECORD CHAR(10); / 入力レコード領域 /
DCL RAW_VAL FIXED DEC(9, 4) VALUE(12345.6789);
DCL SAFE_VAL FIXED DEC(5, 2); / 整数3桁、小数2桁 /
DCL 1 ERROR_CNT FIXED BIN(31) INIT(0);

/ — SIZE条件(オーバーフロー)の捕捉設定 — /
ON SIZE
BEGIN;
PUT SKIP EDIT (‘ [WARNING] SIZE OVERFLOW DETECTED! ‘)
(A);
PUT SKIP EDIT (‘RAW_VAL was truncated or overflowed.’) (A);
ERROR_CNT = ERROR_CNT + 1;
/ 異常値を安全な上限値に丸めるなどのリカバリ処理をここに記述 /
SAFE_VAL = 999.99;
GOTO RESUME_POINT;
END;

PUT SKIP EDIT (‘=== PRECISION FUNCTION TEST START ===’) (A);

/ — ケース1: 正常な精度縮小(切り捨ての確認) — /
/ 元データ(9,4)を、(5,2)のプレシジョンに安全にダウンサイジング /
SAFE_VAL = PRECISION(RAW_VAL, 5, 2);

PUT SKIP EDIT (‘RAW_VAL : ‘, RAW_VAL) (A, F(10,4));
PUT SKIP EDIT (‘SAFE_VAL: ‘, SAFE_VAL)(A, F(6,2));
/ 結果: SAFE_VAL は 345.67 になる(整数部123が入り切らずロストするか、 /
/ あるいはプレシジョン定義次第でSIZE条件が発火する) /

/ — ケース2: 意図的なSIZE条件(オーバーフロー)の誘発 — /
PUT SKIP EDIT (‘— OVERFLOW TEST —‘) (A);

/ 整数部が絶対に収まらない巨大な値を無理やり小さなプレシジョンへ /
SAFE_VAL = PRECISION(99999.99, 3, 2);

RESUME_POINT:

PUT SKIP EDIT (‘PROCESSING COMPLETED. ERROR_COUNT=’, ERROR_CNT)
(A, F(5));

RETURN;
END PREC01P;

このコードのポイント

1. `ON SIZE` ユニットの配置:
代入文や計算式の評価で桁あふれが起きると、即座に `ON SIZE` ブロックへ制御がジャンプする。ここで適切なエラーログを出力し、処理を続行(`GOTO` による復帰)させるか、安全にABENDさせるかを制御するのがプロフェッショナルの実装だ。
2. `PRECISION` の戻り値の属性:
`PRECISION(RAW_VAL, 5, 2)` は、式の結果として `FIXED DEC(5, 2)` の属性を持つ一時的な値を作り出す。これを `SAFE_VAL` に代入するわけだが、元の `RAW_VAL` の整数部が `5 – 2 = 3` 桁(つまり最大999まで)に収まらない場合、コンパイラや実行時は警告やエラーを発する。上記の例では `12345.6789` の整数部 `12345` は 3桁に入りきらないため、厳密には `ON SIZE` が火を吹くか、処理系によっては上位桁が切り捨てられる。

—

5. ベテランからのアドバイス:保守・マイグレーション時の心得

オープン系(C#やJavaなど)から移行してきた若いエンジニアは、「桁あふれなんて自動でよしなにやってくれるだろう」とタカをくくっていることが多い。しかし、メインフレームのPL/Iの世界では、定義されたデータ長に対する厳格さがシステム全体の信頼性を担保している。

もし君が現在、古いCOBOLやPL/Iプログラムの改修や、クラウド移行のためのコード解析を行っているなら、以下のチェックリストを必ず頭に叩き込んでおいてほしい。

  • 暗黙の代入に頼るな: 異なる属性間での代入、特に `FIXED DEC` の桁数が小さくなる代入には、必ず `PRECISION` 関数を明示するか、あらかじめ範囲チェック(バリデーション)を挟め。
  • `ON SIZE` ユニットの有無を確認せよ: 既存の大規模バッチで `ON SIZE` がどこにも定義されていない場合、それは「エラーが起きたら即座に問答無用でABENDする」という設計か、あるいは「単に誰もリスクに気づいていない」かのどちらかだ。後者の場合、データ量が増えた瞬間に本番障害を起こす。
  • コンパイラオプションの確認: `STGOWFL` や `FIXEDOVERFLOW` に関連するコンパイラ時の一時設定(OPTIMIZEレベルによる挙動の変化など)にも気を配ること。

基礎的な構文に見えて、実は基幹システムの堅牢性を左右する奥深いテーマが、この `PRECISION` 関数とデータ制御の世界だ。今回の解説を、君の次のバッチ改修やコードレビューに役立ててほしい。健闘を祈る!

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