こんにちは!IBMメインフレームの世界へようこそ。
JavaやCOBOLといった他のプログラミング言語の経験がおありなら、「よし、新しい言語を覚えるぞ!」と意気込んでいることでしょう。
でも、目の前にそびえ立つレガシーなPL/I(ピーエルアイ)のソースコードを見て、「うわっ、なんだこの独特な書き方は…」と少し気圧されていませんか?大丈夫です、怖くありませんよ。一つずつ紐解いていけば、意外とシンプルで合理的な仕組みになっていることが分かります。
今回は、数あるPL/Iの機能の中でも、バッチ処理の計算やデータ移行で「絶対に避けては通れない実務のキモ」である、ビルトイン関数 `FIXED` による精度の調整について、現場のノウハウを交えながら優しく解説していきますね。
—
そもそもPL/Iの変数って、他言語となにが違うの?
JavaやC言語なら `int` や `double`、COBOLなら `PIC 9(5)V92` のようにデータの型や桁数を指定しますよね。PL/Iも基本は似ているのですが、少し毛色が違います。
まず、PL/Iには「Javaの `final` のような厳密な予約語(変数名に使えない単語)の概念がほぼ無い」という、初心者泣かせの(あるいは自由度の高い)特徴があります。極端な話、ビルトイン関数の名前すら変数名として使えてしまうため、ソースコードを読むときはちょっと注意が必要です。
そして、数値データは主に `FIXED`(固定小数点)や `FLOAT`(浮動小数点)という属性で宣言します。
例えば、こんな風に書きます。
1
DCL WK-KINGAKU FIXED DEC(9, 2); / 9桁のうち、小数点が下2桁の固定小数点数 /
「ほうほう、9桁で小数2位ね」と分かりますよね。
では、この `WK-KINGAKU` に対して、複雑な割り算や掛け算を行ったとき、一体何が起きるでしょうか?
そう、「桁あふれ(Overflow)」や、「端数の無限ループ(丸め誤差)」という、金融系システムでは絶対に許されない悪夢が忍び寄ってくるのです。
—
計算結果の精度が暴走する?そこで登場するのが `FIXED` 関数
例えば、単価と数量を掛け合わせて、さらに税率や割引率を計算するバッチプログラムを想像してください。
PL/Iでは、計算の途中で勝手に「中間結果の精度」が自動拡張されます。これが便利に見えて、実は厄介な曲者です。
「あれ? 想定より小数点の桁数が多すぎて、次の項目に値を代入したときに桁落ちしちゃったよ……」
なんてトラブル、メインフレームのマイグレーション現場では本当によくある話です。
ここで、私たちが意図した「特定の精度」にバシッと強制的に形を整えてくれるのが、ビルトイン関数 `FIXED` なんです。
FIXED関数の基本構文
`FIXED` 関数は、一般的に次のように使います。
1
FIXED ( 式, 整数部・小数部の桁数 [, 小数点以下の桁数] )
なんだか文字だけだと難しそうに見えますよね。
イメージとしては、「あふれそうになったり、細かくなりすぎたりしたプールの水を、決まったサイズの水槽にザバーッと移し替えて、綺麗に形を整える型枠(フレーム)」のようなものです。
—
【実践】実務で使えるPL/Iコード例
百聞は一見にしかず。実際のバッチプログラムでどのように `FIXED` が使われているか、サンプルコードを見てみましょう。
1
————————————————————–
- 顧客別売上計算サンプルプログラム
————————————————————–
SALES-CALC: PROC OPTIONS(MAIN);
/ 変数宣言 /
Dcl Wk-Tanka Fixed Dec(7, 2) Init(1234.56); / 単価 /
Dcl Wk-Suryo Fixed Dec(5, 0) Init(3); / 数量 /
Dcl Wk-Bairitu Fixed Dec(3, 2) Init(1.08); / 係数(税等) /
/ 計算結果を格納する変数(あらかじめ精度を定義) /
Dcl Wk-Kingaku Fixed Dec(9, 2); / 最終金額 /
———————————————————-
- 【パターンA】そのまま計算して代入する場合(危険な香り…)
———————————————————-
- 単価 × 数量 × 倍率 をそのまま突っ込むと、
- PL/Iの内部計算ルールで精度が勝手に膨らみ、
- 予期せぬ丸めやコンパイラの警告(IBMCOBならぬIBM-PL/IのIメッセージ)が出る原因に。
Wk-Kingaku = Wk-Tanka Wk-Suryo Wk-Bairitu;
———————————————————-
- 【パターンB】FIXED関数で安全に精度をコントロール(おすすめ!)
———————————————————-
- 計算の途中で FIXED 関数をかませて、
- 「ここで一度、小数第2位までの形に整えなさい!」と指示します。
Wk-Kingaku = FIXED( Wk-Tanka Wk-Suryo Wk-Bairitu, 9, 2 );
put skip list( ‘計算後の金額 = ‘, Wk-Kingaku );
END SALES-CALC;
このコードのポイントは、パターンBの `FIXED( …, 9, 2 )` の部分です。
「計算結果がどうなろうとも、全体で9桁、うち小数部は2桁にビシッと切り詰めて(または四捨五入して)代入してね」と、コンパイラに強く意思表示をしているわけですね。
—
現場で役立つ!FIXED関数こぼれ話(切り捨てか、四捨五入か?)
ここで、他言語の経験者からよくある質問をひとつ。
「COBOLの `ROUNDED` のように、四捨五入されるの? それとも切り捨て?」
実は、PL/Iの `FIXED` ビルトイン関数による精度の変更は、基本的に「四捨五入(正確には算術丸め)」として動作します。
もし、「いやいや、金融の端数処理だから、何があっても容赦なく切り捨て(Truncate)にしたいんだ!」という場合は、`TRUNC` 関数と組み合わせるか、あるいは代入先の変数の属性(宣言時の桁数)の性質をうまく利用してコントロールする必要があります。このあたりは、レガシーシステムの設計書(仕様書)の「端数処理ルール」の記述と突き合わせながら慎重に実装するポイントですね。
—
最後に:レガシーコードも怖くない!
PL/Iの構文や `FIXED` のようなビルトイン関数は、最初は暗号のように見えるかもしれません。でも、今回お伝えしたように「データの器(サイズ)を強制的に整える便利ツール」だと捉えれば、ぐっと親しみやすくなったのではないでしょうか。
メインフレームのモダナイゼーションや日々の保守運用において、こうしたデータの精度制御はシステムの信頼性を守るための要(かなめ)です。
「一つずつ紐解けば、怖くない!」
その気持ちを忘れずに、ぜひ日々のPL/Iコーディングや移行作業を楽しんでいきてくださいね。あなたのメインフレームライフを、陰ながら応援しています!
