【実務・中級編】PICTURE属性における’V’(仮想小数点)の内部保持形式 – PL/Iの基本構文とデータ制御実践ガイド

おい、新人くん。今日も元気にメインフレームと向き合っているか?
「画面の向こうの黒い画面」に流れるログを見て、冷や汗をかいている姿が目に浮かぶようだ。

今回は、PL/Iのデータ制御において避けて通れない、そして勘違いしていると夜間バッチの真っ最中に盛大にゾーン十進数エラー(S0C7だ!あれは本当に嫌な顔をさせる)を引き起こす魔物、PICTURE属性の仮想小数点「V」と、その内部保持形式(COMP-3:パック10進数)について徹底的に叩き込んでやろう。

COBOLer上がりの連中によくある勘違いだが、「PL/Iは予約語がないから自由度が高いぜ」なんて油断していると、このデータ定義の罠に足元をすくわれる。しっかりとついてきなさい。

1. そもそもPL/Iの「V」とは何者か?

PL/IのPICTURE(PIC)句で使える `V` は、「仮想小数点(Virtual Decimal Point)」を表す。
ここで絶対に忘れてはならない鉄則がある。

> `V` は、メモリ上の物理的な領域を一切消費しない。

例えば、ソースコード上で `DCL 01 WS-AMNT PIC ’99V99′ COMP-3;` と定義したとする。
「9」が4桁、「V」が1文字で、合計5バイト使っているように見えるかい?
大間違いだ。 メモリ(およびVSAMやQSAMのレコードファイル)上でこいつが占有するバイト数は、たったの3バイトだ。

なぜ3バイトになるのか? それがこれから解説する「パック10進数(COMP-3)」の魔法と、仮想小数点の実体なのだ。

2. 内部保持形式(COMP-3)のリアルな構造

IBMメインフレームの世界において、計算効率とストレージ節約の王様といえば `COMP-3`(パック10進数)だ。
1バイト(8ビット)の中に、10進数の数字を2桁(ニブル単位で4ビットずつ)詰め込み、最後の右端の4ビットに符号(正負)を置く。

先ほどの `PIC ’99V99′ COMP-3` を例に、メモリ上のバイトイメージを覗いてみよう。
値として `12.34` を代号(ストア)したとする。

  • 文字列表現(人間が見る形): `1234` (小数点Vの位置は概念上のもの)
  • パック10進数の内部表現(16進数): `01 23 4C`

これを分解してみよう。
1. 第1バイト: `0` と `1` (`01`)
2. 第2バイト: `2` と `3` (`23`)
3. 第3バイト: `4` と 符号の `C` (`4C` ※正の値なので通常はC)

見てみなさい。「V」の文字のための専用領域なんて、どこにも存在しないだろう?
コンパイラは、`V` がどこにあるか(この場合は整数部2桁、小数部2桁の境界)をコンパイル時の属性情報として厳密に記憶しているだけなのだ。

実務において、VSAMファイルから未定義の生データ(ダンプログなど)をブラウザで覗いたとき、「あれ?小数点が入るはずの場所になんの区切りもないぞ?」とパニックになる若手を毎年のように見るが、これで理由が分かったはずだ。`V` は「見えない壁」なのだよ。

3. 実践:VSAM入出力とONユニットによるデータ例外制御

では、この仮想小数点を持つデータを、実際のバッチプログラムでどう扱うか。
VSAMレコードの入出力、および万が一不正データ(スペースや非数値文字)が混入した際にプログラムをクラッシュさせないための `ON ERROR`(ONユニット)の活用法を含めた、実用的なPL/Iソースコードを示す。

大文字ベースの記述、BUILTIN関数の活用、そして現場の作法に則った丁寧なコメントを確認してほしい。

//
/ プログラム名: VDEC0100 /
/ 概要 : PICTURE ‘V’(仮想小数点)を持つCOMP-3項目の /
/ 演算処理およびVSAM入出力のサンプル /
//
VDEC0100: PROC OPTIONS(MAIN);

/ — 1. 宣言部 — /
/ 入力用VSAMレコード(物理的には純粋なバイト列) /
DCL 1 IN-RECORD,
05 IN-ID CHAR(5), / 顧客ID /
05 IN-PRICE PIC ‘9999V99’ COMP-3; / 単価(実体3バイト) /

/ 演算・編集用ワーク /
DCL WK-TAX-RATE PIC ‘V99’ VALUE ‘.08’ COMP-3; / 消費税率8% /
DCL WK-TOTAL PIC ‘99999V99’ COMP-3; / 税込金額(5バイト)/
DCL OUT-MSG CHAR(80); / ログ出力用 /

/ ファイル定義(QSAM/VSAM) /
DCL SALES-FILE FILE RECORD INPUT;
DCL PRINT-FILE FILE STREAM OUTPUT;

/ フラグ定義 /
DCL EOF-FLG BIT(1) INIT(‘0’B);

/ — 2. 異常系トラップ(ONユニット)の設定 — /
/ メモリ上のパック10進数データが破損している場合のS0C7対策 /
ON CONVERSION BEGIN;
PUT SKIP EDIT (‘【重篤エラー】データ変換例外が発生しました。値が不正です。ID: ‘, IN-ID)
(A, A);
/ 実務ではここでエラースプールへの出力や異常終了コード設定を行う /
SIGNAL ERROR;
END;

/ — 3. ファイルオープン — /
OPEN FILE(SALES-FILE) INPUT,
FILE(PRINT-FILE) OUTPUT;

/ — 4. メイン処理ループ — /
DO WHILE (^EOF-FLG);

READ FILE(SALES-FILE) INTO(IN-RECORD);

/ 標準的なファイル終了(EOF)判定 /
IF EOF-FLG THEN LEAVE;

/ — 仮想小数点を含んだ算術演算 — /
/ PL/Iは「V」の位置を自動的に認識して小数点を揃えた算術演算を行う /
/ COBOLのようにわざわざSCALEを気にしてシフトする必要はない /
WK-TOTAL = IN-PRICE + (IN-PRICE WK-TAX-RATE);

/ 組み込み関数(BUILTIN)を使った編集と出力 /
/ 仮想小数点付きのCOMP-3データを、人間が読める文字形式に変換 /
PUT FILE(PRINT-FILE) EDIT
(‘顧客ID: ‘, IN-ID,
‘ 税込金額: ‘, FIXED(WK-TOTAL, 7, 2))
(A(8), A(5), A(12), F(10,2));

END;

/ — 5. 終了処理 — /
CLOSE FILE(SALES-FILE),
FILE(PRINT-FILE);

RETURN;

END VDEC0100;

4. ベテランからの現場の教訓(ココが危ない!)

この `V` 付きCOMP-3を扱うにあたって、過去のバッチ改修で何度も泣かされたポイントを伝授しておこう。

1. 暗黙の桁あふれ(Overflow)に気をつけろ
算術演算の結果、受け側の PICTURE 桁数(特に整数部)に入りきらなくなった場合、PL/Iはデフォルトでは容赦なく上位桁を切り捨てる(あるいはコンテキストによっては大小比較や代入で例外になる)。
特に `V` の位置をまたぐ乗算や除算を行うときは、中間ワークの定義を十分に大きくとるのがプロの技だ。
2. COBOLとのインターフェース(データ共有)の罠
他系統のCOBOLプログラムが吐き出したファイルをPL/Iで読む、あるいはその逆のケース。
COBOL側で `PIC S9(4)V99 COMP-3` と定義されているものは、PL/I側でも完全に一致させないと、パディング(詰め物)の解釈が狂い、データがズタズタになる。必ずCOPY句やレコードレイアウト仕様書のバイト数(Bytes)と PICTURE の整合性を突き合わせる習慣をつけなさい。

仮想小数点 `V` は、メモリを1ビットも無駄にせず、かつプログラムには小数点位置を意識させずに高精度な計算をさせるための、先人たちの知恵の結晶だ。
この構造を頭に叩き込んでおけば、どんな巨大なレガシーシステムのデータ改修が来ようとも、怖気づくことはない。

さあ、次のチケットを片付けに行こうか。質問があったらいつでもエンジニア室に来い。

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