10進数精度(COMP-3 / PACKED-DECIMAL)
『COBOL』の COMP-3(パックド10進数、PACKED-DECIMAL とも呼ばれます)は、金融・保険・行政システムの精密な10進数演算に不可欠な内部数値表現形式です。通常の表示形式(DISPLAY)と異なり、2桁の数字を1バイトに詰め込んで格納するため、メモリ効率が高く、10進数の精度を保ちながら高速な演算が可能になります。
構文
*> ----------------------------------------------- *> COMP-3 / PACKED-DECIMAL — 宣言の基本構文 *> ----------------------------------------------- *> 符号付き整数型(COMP-3) 01 変数名 PIC S9(n) COMP-3. *> 符号付き小数型(COMP-3) 01 変数名 PIC S9(n)V9(m) COMP-3. *> 初期値付きで宣言します 01 変数名 PIC S9(7)V99 COMP-3 VALUE 0. *> ----------------------------------------------- *> COMP-3 変数を使った演算 *> ----------------------------------------------- *> COMPUTE 文での使用(金額計算の例) COMPUTE WS-TOTAL ROUNDED = WS-PRICE * WS-QUANTITY. *> ADD 文での使用 ADD WS-TAX TO WS-TOTAL. *> SUBTRACT 文での使用 SUBTRACT WS-DISCOUNT FROM WS-TOTAL. *> MULTIPLY 文での使用 MULTIPLY WS-RATE BY WS-AMOUNT GIVING WS-RESULT ROUNDED. *> ----------------------------------------------- *> DISPLAY 形式への変換(出力用) *> ----------------------------------------------- *> COMP-3 変数はそのまま DISPLAY できます(自動変換されます) DISPLAY "合計金額: " WS-TOTAL. *> MOVE で DISPLAY 形式の変数に変換して整形出力します MOVE WS-TOTAL TO WS-TOTAL-DISPLAY. DISPLAY "合計金額(編集済み): " WS-TOTAL-DISPLAY.
構文一覧
| 句 / 指定 | 概要 |
|---|---|
COMP-3 | パックド10進数形式で数値を格納する指定です。COMPUTATIONAL-3 または PACKED-DECIMAL とも書けます。 |
PIC S9(n) COMP-3 | 符号付き整数型の COMP-3 変数を宣言します。S を付けないと負の値を格納できません。 |
PIC S9(n)V9(m) COMP-3 | 符号付き小数型の COMP-3 変数を宣言します。整数部 n 桁・小数部 m 桁を確保します。 |
ROUNDED | 演算結果の小数部が変数の精度を超えた場合に四捨五入を行います。金融計算で精度を保つために重要です。 |
ON SIZE ERROR | 演算結果が変数の PIC 句で定義した桁数を超えた場合の例外処理を記述します。 |
COMPUTE 変数 ROUNDED = 式 | 算術式を評価して結果を四捨五入して変数に格納します。COMP-3 変数同士の演算に使います。 |
ADD 値 TO 変数 | 変数に値を加算します。COMP-3 変数に対して直接使えます。 |
SUBTRACT 値 FROM 変数 | 変数から値を減算します。 |
MULTIPLY 値 BY 変数 GIVING 結果変数 | 乗算して結果を別の変数に格納します。GIVING 句で元の変数を変更せずに結果を得られます。 |
DISPLAY 形式(編集 PIC) | COMP-3 の計算結果を人が読める形式に整形して出力するために MOVE で編集 PIC 変数へ転送します。 |
COMPUTATIONAL-3 | COMP-3 の完全な書き方です。動作は同一です。 |
PACKED-DECIMAL | ISO 標準の呼び方です。COMP-3 と同義で使えます(方言によります)。 |
サンプルコード
deathnote_comp3.cbl
*> deathnote_comp3.cbl — COMP-3(パックド10進数)のサンプルです
*> DEATH NOTE のキャラクターを使って
*> COMP-3 宣言・四則演算・ROUNDED 句・ON SIZE ERROR を確認します
*>
*> コンパイルと実行:
*> cobc -free -x deathnote_comp3.cbl
*> ./deathnote_comp3
IDENTIFICATION DIVISION.
PROGRAM-ID. DEATHNOTE-COMP3.
DATA DIVISION.
WORKING-STORAGE SECTION.
*> -----------------------------------------------
*> 捜査官の捜査スコア(DEATH NOTE 捜査チーム)
*> PIC S9(5)V99 COMP-3 — 符号付き、整数5桁・小数2桁
*> -----------------------------------------------
*> Light Yagami の捜査スコア(対キラ捜査)
01 WS-SCORE-LIGHT PIC S9(5)V99 COMP-3 VALUE 98.50.
*> L Lawliet の捜査スコア
01 WS-SCORE-L PIC S9(5)V99 COMP-3 VALUE 99.90.
*> Near の捜査スコア
01 WS-SCORE-NEAR PIC S9(5)V99 COMP-3 VALUE 95.30.
*> -----------------------------------------------
*> 捜査費用の精密計算用(高精度スコア)
*> PIC S9(7)V9(4) COMP-3 — 整数7桁・小数4桁の高精度
*> -----------------------------------------------
*> 各捜査官の予算スコア(基礎値)
01 WS-BUDGET-LIGHT PIC S9(7)V9(4) COMP-3 VALUE 5000.0000.
01 WS-BUDGET-L PIC S9(7)V9(4) COMP-3 VALUE 8500.0000.
01 WS-BUDGET-MISA PIC S9(7)V9(4) COMP-3 VALUE 3200.5000.
*> -----------------------------------------------
*> 計算結果・作業用変数(すべて COMP-3 で統一)
*> -----------------------------------------------
*> 捜査スコアの合計
01 WS-SCORE-TOTAL PIC S9(7)V99 COMP-3 VALUE 0.
*> 捜査スコアの平均
01 WS-SCORE-AVG PIC S9(5)V99 COMP-3 VALUE 0.
*> 補正後の値(乗算結果)
01 WS-SCORE-ADJUSTED PIC S9(7)V9(4) COMP-3 VALUE 0.
*> 補正係数(難易度ボーナス 1.1500)
01 WS-DIFFICULTY-FACTOR PIC S9(1)V9(4) COMP-3 VALUE 1.1500.
*> 予算スコアの合計
01 WS-BUDGET-TOTAL PIC S9(9)V9(4) COMP-3 VALUE 0.
*> 予算スコアの平均
01 WS-BUDGET-AVG PIC S9(7)V9(4) COMP-3 VALUE 0.
*> 桁あふれテスト用(5桁整数のみ)
01 WS-OVERFLOW-TEST PIC S9(5) COMP-3 VALUE 99999.
*> -----------------------------------------------
*> 出力用(編集 PIC)— COMP-3 は DISPLAY 形式へ MOVE して整形します
*> -----------------------------------------------
01 WS-OUT-SCORE PIC ZZ9.99.
01 WS-OUT-AVG PIC ZZ9.99.
01 WS-OUT-BUDGET PIC ZZZZ9.9(4).
01 WS-OUT-BUDGET-AVG PIC ZZZZ9.9(4).
01 WS-OUT-ADJUSTED PIC ZZZZ9.9(4).
PROCEDURE DIVISION.
DISPLAY "====================================".
DISPLAY " DEATH NOTE — 捜査スコア分析レポート".
DISPLAY "====================================".
DISPLAY " ".
*> -----------------------------------------------
*> ADD / SUBTRACT — 捜査スコアの集計
*> COMP-3 変数同士の加算は高速な内部演算で実行されます
*> -----------------------------------------------
DISPLAY "[ ADD — 捜査スコアの合計(COMP-3 加算) ]".
*> 各人物のスコアを順に加算します
ADD WS-SCORE-LIGHT TO WS-SCORE-TOTAL.
ADD WS-SCORE-L TO WS-SCORE-TOTAL.
ADD WS-SCORE-NEAR TO WS-SCORE-TOTAL.
*> COMP-3 変数を編集 PIC へ MOVE して整形表示します
MOVE WS-SCORE-LIGHT TO WS-OUT-SCORE.
DISPLAY " Light Yagami 捜査スコア: " WS-OUT-SCORE.
MOVE WS-SCORE-L TO WS-OUT-SCORE.
DISPLAY " L Lawliet 捜査スコア: " WS-OUT-SCORE.
MOVE WS-SCORE-NEAR TO WS-OUT-SCORE.
DISPLAY " Near 捜査スコア: " WS-OUT-SCORE.
MOVE WS-SCORE-TOTAL TO WS-OUT-SCORE.
DISPLAY " 合計 : " WS-OUT-SCORE.
DISPLAY " ".
*> -----------------------------------------------
*> COMPUTE ROUNDED — 捜査スコアの平均(四捨五入あり)
*> 小数部が精度を超えた場合に ROUNDED で丸めます
*> -----------------------------------------------
DISPLAY "[ COMPUTE ROUNDED — 捜査スコアの平均 ]".
*> 3人の平均を計算します(除算後の端数を四捨五入)
COMPUTE WS-SCORE-AVG ROUNDED = WS-SCORE-TOTAL / 3.
MOVE WS-SCORE-AVG TO WS-OUT-AVG.
DISPLAY " 平均捜査スコア(ROUNDED): " WS-OUT-AVG.
DISPLAY " ".
*> -----------------------------------------------
*> MULTIPLY — 難易度補正係数を掛けた調整値
*> GIVING 句で元の変数を保持しつつ結果を別変数に格納します
*> -----------------------------------------------
DISPLAY "[ MULTIPLY GIVING ROUNDED — 難易度補正後のスコア(L Lawliet) ]".
*> 難易度ボーナス 1.15 を掛けて補正後の捜査スコアを算出します
MULTIPLY WS-DIFFICULTY-FACTOR BY WS-SCORE-L
GIVING WS-SCORE-ADJUSTED ROUNDED.
MOVE WS-SCORE-L TO WS-OUT-SCORE.
DISPLAY " 補正前(L Lawliet): " WS-OUT-SCORE.
MOVE WS-SCORE-ADJUSTED TO WS-OUT-ADJUSTED.
DISPLAY " 補正後 : " WS-OUT-ADJUSTED.
DISPLAY " ".
*> -----------------------------------------------
*> 高精度(V9(4))の予算スコア集計
*> 小数4桁を COMP-3 で扱い、精度を維持して演算します
*> -----------------------------------------------
DISPLAY "[ COMPUTE — 予算スコア合計・平均(小数4桁 COMP-3) ]".
*> 予算スコアを合計します
COMPUTE WS-BUDGET-TOTAL =
WS-BUDGET-LIGHT + WS-BUDGET-L + WS-BUDGET-MISA.
*> 3人の平均を計算します(ROUNDED で4桁目以降を丸めます)
COMPUTE WS-BUDGET-AVG ROUNDED = WS-BUDGET-TOTAL / 3.
MOVE WS-BUDGET-LIGHT TO WS-OUT-BUDGET.
DISPLAY " Light Yagami 予算スコア: " WS-OUT-BUDGET.
MOVE WS-BUDGET-L TO WS-OUT-BUDGET.
DISPLAY " L Lawliet 予算スコア: " WS-OUT-BUDGET.
MOVE WS-BUDGET-MISA TO WS-OUT-BUDGET.
DISPLAY " Misa Amane 予算スコア: " WS-OUT-BUDGET.
MOVE WS-BUDGET-AVG TO WS-OUT-BUDGET-AVG.
DISPLAY " 3人の平均 : " WS-OUT-BUDGET-AVG.
DISPLAY " ".
*> -----------------------------------------------
*> ON SIZE ERROR — 桁あふれの検出
*> PIC S9(5) の変数に 99999 の2乗(9999800001)を格納しようとします
*> -----------------------------------------------
DISPLAY "[ ON SIZE ERROR — COMP-3 桁あふれ検出 ]".
DISPLAY " テスト変数(PIC S9(5) COMP-3)初期値: 99999".
COMPUTE WS-OVERFLOW-TEST = WS-OVERFLOW-TEST * WS-OVERFLOW-TEST
ON SIZE ERROR
DISPLAY " 桁あふれ検出!変数の値は変更されませんでした。"
NOT ON SIZE ERROR
DISPLAY " 演算成功: " WS-OVERFLOW-TEST
END-COMPUTE.
DISPLAY " ".
DISPLAY "====================================".
DISPLAY " キラ捜査スコア分析完了。".
DISPLAY "====================================".
*> STOP RUN でプログラムを正常終了します
STOP RUN.
cobc -free -x deathnote_comp3.cbl && ./deathnote_comp3 ==================================== DEATH NOTE — 捜査スコア分析レポート ==================================== [ ADD — 捜査スコアの合計(COMP-3 加算) ] Light Yagami 捜査スコア: 98.50 L Lawliet 捜査スコア: 99.90 Near 捜査スコア: 95.30 合計 : 293.70 [ COMPUTE ROUNDED — 捜査スコアの平均 ] 平均捜査スコア(ROUNDED): 97.90 [ MULTIPLY GIVING ROUNDED — 難易度補正後のスコア(L Lawliet) ] 補正前(L Lawliet): 99.90 補正後 : 114.8850 [ COMPUTE — 予算スコア合計・平均(小数4桁 COMP-3) ] Light Yagami 予算スコア: 5000.0000 L Lawliet 予算スコア: 8500.0000 Misa Amane 予算スコア: 3200.5000 3人の平均 : 5566.8333 [ ON SIZE ERROR — COMP-3 桁あふれ検出 ] テスト変数(PIC S9(5) COMP-3)初期値: 99999 桁あふれ検出!変数の値は変更されませんでした。 ==================================== キラ捜査スコア分析完了。 ====================================
概要
『COBOL』の COMP-3(PACKED-DECIMAL)は、2桁の10進数字を1バイトに詰め込む内部表現形式です。通常の DISPLAY 形式が1桁につき1バイトを使うのに対し、COMP-3 は n 桁の数値を (n + 1) / 2 バイトで格納するため、メモリ効率が大幅に向上します。さらに演算時も10進数の精度をそのまま維持できるため、浮動小数点数(COMP-1/COMP-2)で生じる丸め誤差が発生しません。これが金融・保険・税務システムで COMP-3 が長年使われてきた理由です。宣言時は PIC S9(n)V9(m) COMP-3 のように符号 S を付けておくことが推奨されます(符号なしだと負の結果を保持できず、演算誤差の原因になります)。演算後の丸めには ROUNDED 句を使い、桁あふれの検出には ON SIZE ERROR 句を組み合わせます。画面出力時は COMP-3 変数を編集 PIC(ZZZ9.99 など)の変数に MOVE してから DISPLAY すると、読みやすい形式で表示できます。数値 PIC 句の基礎については PIC句(数値型) を、COMPUTE 文の演算詳細については COMPUTE を合わせて確認できます。
よくあるミス
ミス1: COMP-3は桁数が奇数でも内部的にはバイト単位で丸め
COMP-3 は2桁を1バイトに格納する形式で、最後のバイトには最後の1桁と符号が入ります。PIC S9(5) COMP-3 は5桁なので、内部的には3バイトが使われます((5 + 1) / 2 = 3)。桁数を大きく設定してもバイト数は切り上げで計算されます。
*> COMP-3 のバイト数は (n + 1) / 2 で計算されます
*> PIC S9(5) COMP-3 — 5桁 → (5+1)/2 = 3バイト
*> PIC S9(7) COMP-3 — 7桁 → (7+1)/2 = 4バイト
*> PIC S9(4) COMP-3 — 4桁 → (4+1)/2 = 2.5 → 3バイト(切り上げ)
*> Light Yagami の捜査分析スコアでバイト効率を確認します
01 WS-SCORE-5DIG PIC S9(5) COMP-3 VALUE 12345. *> 3バイト
01 WS-SCORE-6DIG PIC S9(6) COMP-3 VALUE 123456. *> 4バイト(5桁と同じバイト数)
PROCEDURE DIVISION.
DISPLAY "5桁スコア: " WS-SCORE-5DIG.
DISPLAY "6桁スコア: " WS-SCORE-6DIG.
STOP RUN.
L Lawliet が正確な情報を把握するように、COMP-3 のバイト数は (n + 1) / 2 の計算式で事前に見積もります。6桁と5桁が同じバイト数になる点を意識して宣言します。
ミス2: V(小数点)のある変数をDISPLAYすると小数点は表示されない
PIC S9(5)V99 COMP-3 のように V(仮想小数点)を定義した変数を、そのまま DISPLAY すると小数点は表示されません。V は内部の位置を示すだけで表示には影響しないためです。
*> NG: V があってもそのまま DISPLAY すると小数点が表示されません
01 WS-SCORE PIC S9(5)V99 COMP-3 VALUE 98.50.
PROCEDURE DIVISION.
DISPLAY "Near のスコア: " WS-SCORE.
*> 結果は "009850" のように小数点なしで表示されます
STOP RUN.
Misa Amane が見やすいスタイルにこだわるように、小数点付きで表示したい場合は編集 PIC 変数(ZZ9.99 など)に MOVE してから DISPLAY します。
*> OK: 編集 PIC 変数に MOVE してから DISPLAY します
01 WS-SCORE PIC S9(5)V99 COMP-3 VALUE 98.50.
01 WS-SCORE-DISP PIC ZZ9.99.
PROCEDURE DIVISION.
MOVE WS-SCORE TO WS-SCORE-DISP.
DISPLAY "Near のスコア: " WS-SCORE-DISP.
*> 結果: " 98.50" と正しく表示されます
STOP RUN.
ミス3: 演算後の精度がPIC桁数を超えると切り捨てられる
演算後の結果が格納先変数の PIC 句で定義した桁数・精度を超えると、超えた部分は切り捨てられます。ROUNDED 句を使わないと四捨五入もされません。
*> NG: 除算の結果が PIC の精度を超えると小数部が切り捨てられます
01 WS-TOTAL PIC S9(7)V99 COMP-3 VALUE 293.70.
01 WS-AVG-NG PIC S9(5)V99 COMP-3 VALUE 0.
01 WS-OUT-AVG PIC ZZ9.99.
PROCEDURE DIVISION.
COMPUTE WS-AVG-NG = WS-TOTAL / 3.
*> 293.70 / 3 = 97.90... 小数3桁目以降が切り捨てられます
MOVE WS-AVG-NG TO WS-OUT-AVG.
DISPLAY "平均(切り捨て): " WS-OUT-AVG.
STOP RUN.
Light Yagami が完璧な計画を立てるように、精度が必要な演算では ROUNDED 句を付けて四捨五入するか、格納先の変数の小数桁数を十分に大きくしておきます。
*> OK: ROUNDED 句を使って四捨五入します
01 WS-TOTAL PIC S9(7)V99 COMP-3 VALUE 293.70.
01 WS-AVG-OK PIC S9(5)V99 COMP-3 VALUE 0.
01 WS-OUT-AVG PIC ZZ9.99.
PROCEDURE DIVISION.
COMPUTE WS-AVG-OK ROUNDED = WS-TOTAL / 3.
MOVE WS-AVG-OK TO WS-OUT-AVG.
DISPLAY "平均(ROUNDED): " WS-OUT-AVG.
*> 結果: " 97.90" と正しく表示されます
STOP RUN.
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。