【入門編】固定小数点演算におけるオーバーフロー条件 – PL/Iの基本構文とデータ制御実践ガイド

こんにちは!メインフレームの世界へようこそ。
JavaやCOBOLといったモダン、あるいはビジネス寄りの言語をバリバリ書いてきた方にとって、IBMメインフレームの「PL/I(ピーエルワン)」という名前を聞くだけで、なんだか古めかしくて難解な要塞のように感じてしまうかもしれませんよね。

「なんだか変数宣言が独特だし、ポインタや複雑なデータ構造がありそう……」
「もし計算結果が変数の入れ物に入りきらなくなったら、プログラムがいきなり異常終了しちゃうんじゃないの?」

そんな不安を抱えているあなたへ。大丈夫です、怖くありませんよ。一つずつ蓋を開けて中身を覗いていけば、PL/Iも他の言語と本質は同じ、むしろ非常にロジカルで優しい言語であることがわかります。

今回は、基幹システムのバッチ処理などで最も頻繁に登場する「固定小数点数(FIXED BINARY / DECIMAL)」の計算と、そこでおこる「オーバーフロー(SIZE条件)」について、じっくり紐解いていきましょう。

—

1. 他の言語とはちょっと違う? PL/Iの「固定小数点数」のキホン

Javaなら `int` や `long`、COBOLなら `PIC 9(9) COMP` のように、数値を扱うためのデータ型はどの言語にもありますよね。PL/Iでも基本は一緒なのですが、宣言の仕方にちょっと独特のこだわりがあります。

PL/Iで固定小数点数を扱うときは、主に以下の2つを使います。

  • FIXED DECIMAL(固定小数点十進数): 金額や数量など、人間の感覚に合わせた10進数で正確に計算したいときに使います(COBOLのゾーン decimal やパック decimal に近いです)。
  • FIXED BINARY(固定小数点二進数): コンピュータが一番得意とする2進数で、ループのカウンタやフラグ、内部的な数値処理によく使われます(Javaの `int` や `short` のイメージです)。

謎の数字 `(5, 2)` ってなに?

PL/Iのコードを見ていると、こんな宣言に出会ってギョッとしたことがあるかもしれません。

1
DCL WK-KINGAKU FIXED DECIMAL(5, 2);

「なんだこのカッコの数字は……?」って思いますよね。
これは、「全体で何桁(精度)」あって、そのうち「小数点が右から何桁分あるか(スケール)」を示しています。

  • `5`:全体の桁数(精度 / Precision)= 5桁
  • `2`:小数点以下の桁数(スケール / Scale)= 2桁

つまり、この `WK-KINGAKU` という入れ物は、整数部が3桁、小数部が2桁入る箱ということになります。格納できる最大の数値は `999.99`、最小は `-999.99` です。この「入れ物のサイズ(器の大きさ)」をプログラマが細かく指定できるのが、PL/Iの大きな特徴であり、強力なところなんです。

—

2. 器に入りきらない!「オーバーフロー」の恐怖とSIZE条件

さて、ここからが本題です。
精巧に作られたこの「数字の入れ物」ですが、世の中そんなに甘くありません。バッチ処理で大量のデータを処理していると、思わすこんな事態が起きます。

> 「計算結果が、用意した箱の大きさをオーバーしてしまった!」

例えば、先ほどの `FIXED DECIMAL(5, 2)`(最大 `999.99`)の変数に、売上と単価を掛け合わせた結果、`1250.50` という値が入ろうとしたとします。
整数部は「3桁」必要なのに、入る席が足りませんよね。これがオーバーフローです。

他の言語(例えばC言語など)では、こういうときにこっそり上位桁が切り捨てられたり、おかしなゴミデータになって後続処理に悪影響を与えたりして、原因究明に何日も悩まされる……なんてことがよくあります。

しかし、そこは天下のIBMメインフレーム、そしてPL/Iです。PL/Iには、この「箱に入りきらない悲劇」を検知し、プログラムが勝手に暴走するのを防ぐための素晴らしい仕組みが標準で備わっています。それが「SIZE条件(SIZE Condition)」です。

—

3. ON SIZEユニットで華麗にエラーをキャッチしよう

PL/Iでは、万が一オーバーフローが発生したときにどう動くかを、あらかじめ `ON` 句という構文で指定しておくことができます。これを「ONユニット」と呼びます。

百聞は一見に如かず、実際のコードを見てみましょう。実務のマイグレーション調査でもそのまま読めるように、分かりやすいコメントをつけておきました。

1
/ ========================================================== /
/ 固定小数点演算のオーバーフロー(SIZE条件)制御サンプル /
/ ========================================================== /
TEST_CALC: PROC OPTIONS(MAIN);

/ 変数の宣言 /
DCL W_TANKA FIXED DECIMAL(5, 2) INIT(150.00); / 単価:全体5桁、小数2桁 /
DCL W_SURYO FIXED DECIMAL(4, 0) INIT(10.00); / 数量:全体4桁、小数0桁 /
DCL W_GOKEI FIXED DECIMAL(6, 2); / 合計:全体6桁、小数2桁 /

/ SIZE条件の監視を開始する(オーバーフローが起きたらここへジャンプ!) /
ON SIZE BEGIN;
PUT SKIP LIST(‘【警告】計算結果が変数の大きさを超過しました!’);
PUT SKIP LIST(‘安全装置が作動したため、処理を継続または安全に中断します。’);

/ ここで異常終了コードを設定したり、エラーログ用の退避処理を書くことができます /
GOTO ERROR_ROUTINE;
END;

/ — 通常の計算処理 — /
/ 150.00 10.00 = 1500.00 だが、W_GOKEI の大きさは FIXED DECIMAL(6, 2) なので入る /
W_GOKEI = W_TANKA W_SURYO;
PUT SKIP EDIT (‘正常計算結果:’, W_GOKEI) (A, F(10,2));

/ — わざとオーバーフローを発生させる意地悪な計算 — /
/ W_GOKEI の整数部は 4桁(全体6 – 小数2)まで。 /
/ もっと大きな数字をブッ込んでみます。 /
W_GOKEI = 99999.99; / おっと、これだと入らない! /

PUT SKIP LIST(‘この行はオーバーフローが起きているためスキップされます’);

RETURN;

ERROR_ROUTINE:
PUT SKIP LIST(‘==> 異常時のお片付け処理を実行して安全に終了します。’);
RETURN;

END TEST_CALC;

このコードのポイント

1. `ON SIZE BEGIN … END;`
このブロックを宣言しておくと、プログラム実行中に `SIZE` 条件(データの切り捨てを伴うオーバーフロー)が発生した瞬間、自動的にこの中に制御が飛びます。
2. サイレントエラーを防ぐ
「気づかないうちにデータが壊れていた」というレガシーシステム特有の最も恐ろしいバグを、この `ON SIZE` によってその場で検知し、安全にハンドリング(あるいは異常終了)させることができます。

—

4. アーキテクトからの実務アドバイス:なぜこの知識が移行時に重要なのか?

現代のオープン系言語(JavaやC#など)に慣れたエンジニアからすると、「なんでわざわざ桁数を細かく指定して、しかもオーバーフローの監視なんて書かなきゃいけないの?」と思われるかもしれません。

しかし、金融や公共などの基幹システムを支えるメインフレームの世界では、「1円のズレも許されない」「不正なデータで2次災害を起こしてはならない」という厳格な要件が何十年も求められ続けてきました。

もしあなたが今後、COBOLやPL/Iで書かれたレガシーシステムをJavaや他のモダン言語へマイグレーション(移行)するプロジェクトに関わるとしたら、この「PL/Iが暗黙的に行っていた精度制御やオーバーフロー検知」の挙動をしっかりと読み解く必要があります。
「元のPL/Iコードでは、ここで `SIZE` 条件をトラップしてデフォルト値を代入していたのか!」という気づきが、移行先の新しいプログラムでバグを防ぐ大きなヒントになるのです。

—

まとめ

  • FIXED DECIMAL / BINARY の宣言にあるカッコの数字 `(精度, スケール)` は、データの「器の大きさ」を決める大切な設計図。
  • 器に入りきらない計算結果が発生したときは、SIZE条件がそれを検知してくれる。
  • `ON SIZE` ユニットを使えば、予期せぬオーバーフローからシステムを優しく、かつ確実に守ることができる。

PL/Iは一見すると取っつきにくいですが、データ管理に対する責任感が非常に強い、実直で頼れる相棒のような言語です。
「怖くないですよ、一つずつ紐解けば簡単です」。この調子で、メインフレームの海を一緒に楽しく渡っていきましょう!

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