Decimal Precision (COMP-3 / PACKED-DECIMAL)
In COBOL, COMP-3 (packed decimal, also called PACKED-DECIMAL) is an internal numeric representation format essential for precise decimal arithmetic in financial, insurance, and government systems. Unlike the normal display format (DISPLAY), it packs two decimal digits into one byte, providing high memory efficiency and enabling fast arithmetic while maintaining decimal precision.
Syntax
*> ----------------------------------------------- *> COMP-3 / PACKED-DECIMAL — Basic declaration syntax *> ----------------------------------------------- *> Signed integer type (COMP-3) 01 var-name PIC S9(n) COMP-3. *> Signed decimal type (COMP-3) 01 var-name PIC S9(n)V9(m) COMP-3. *> Declare with an initial value 01 var-name PIC S9(7)V99 COMP-3 VALUE 0. *> ----------------------------------------------- *> Arithmetic using COMP-3 variables *> ----------------------------------------------- *> Use in a COMPUTE statement (example: price calculation) COMPUTE WS-TOTAL ROUNDED = WS-PRICE * WS-QUANTITY. *> Use in an ADD statement ADD WS-TAX TO WS-TOTAL. *> Use in a SUBTRACT statement SUBTRACT WS-DISCOUNT FROM WS-TOTAL. *> Use in a MULTIPLY statement MULTIPLY WS-RATE BY WS-AMOUNT GIVING WS-RESULT ROUNDED. *> ----------------------------------------------- *> Converting to DISPLAY format (for output) *> ----------------------------------------------- *> COMP-3 variables can be displayed directly (auto-converted) DISPLAY "Total amount: " WS-TOTAL. *> MOVE to a DISPLAY-format variable for formatted output MOVE WS-TOTAL TO WS-TOTAL-DISPLAY. DISPLAY "Total amount (formatted): " WS-TOTAL-DISPLAY.
Syntax Reference
| Clause / Specification | Description |
|---|---|
COMP-3 | Specifies that a numeric value is stored in packed decimal format. Can also be written as COMPUTATIONAL-3 or PACKED-DECIMAL. |
PIC S9(n) COMP-3 | Declares a signed integer COMP-3 variable. Without S, negative values cannot be stored. |
PIC S9(n)V9(m) COMP-3 | Declares a signed decimal COMP-3 variable. Allocates n integer digits and m fractional digits. |
ROUNDED | Rounds the result when the fractional part of the arithmetic result exceeds the variable's precision. Important for maintaining accuracy in financial calculations. |
ON SIZE ERROR | Specifies exception handling for when the arithmetic result exceeds the number of digits defined in the variable's PIC clause. |
COMPUTE variable ROUNDED = expression | Evaluates an arithmetic expression, rounds the result, and stores it in a variable. Used for operations between COMP-3 variables. |
ADD value TO variable | Adds a value to a variable. Can be used directly with COMP-3 variables. |
SUBTRACT value FROM variable | Subtracts a value from a variable. |
MULTIPLY value BY variable GIVING result-variable | Multiplies and stores the result in another variable. The GIVING clause lets you get the result without modifying the original variable. |
| DISPLAY format (edit PIC) | To format COMP-3 calculation results in a human-readable form, MOVE them to an edit PIC variable before output. |
COMPUTATIONAL-3 | The full spelling of COMP-3. Behavior is identical. |
PACKED-DECIMAL | The ISO standard name. Can be used as a synonym for COMP-3 (dialect-dependent). |
Sample Code
deathnote_comp3.cbl
*> deathnote_comp3.cbl — Sample for COMP-3 (packed decimal)
*> Uses DEATH NOTE characters to demonstrate
*> COMP-3 declarations, arithmetic, the ROUNDED clause, and ON SIZE ERROR
*>
*> Compile and run:
*> cobc -free -x deathnote_comp3.cbl
*> ./deathnote_comp3
IDENTIFICATION DIVISION.
PROGRAM-ID. DEATHNOTE-COMP3.
DATA DIVISION.
WORKING-STORAGE SECTION.
*> -----------------------------------------------
*> Investigation scores for the DEATH NOTE investigation team
*> PIC S9(5)V99 COMP-3 — signed, 5 integer digits, 2 fractional digits
*> -----------------------------------------------
*> Light Yagami's investigation score (Kira investigation)
01 WS-SCORE-LIGHT PIC S9(5)V99 COMP-3 VALUE 98.50.
*> L Lawliet's investigation score
01 WS-SCORE-L PIC S9(5)V99 COMP-3 VALUE 99.90.
*> Near's investigation score
01 WS-SCORE-NEAR PIC S9(5)V99 COMP-3 VALUE 95.30.
*> -----------------------------------------------
*> For precise budget calculation (high-precision scores)
*> PIC S9(7)V9(4) COMP-3 — high precision: 7 integer digits, 4 fractional digits
*> -----------------------------------------------
*> Budget scores for each investigator (base values)
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.
*> -----------------------------------------------
*> Result and work variables (all unified as COMP-3)
*> -----------------------------------------------
*> Total investigation score
01 WS-SCORE-TOTAL PIC S9(7)V99 COMP-3 VALUE 0.
*> Average investigation score
01 WS-SCORE-AVG PIC S9(5)V99 COMP-3 VALUE 0.
*> Adjusted value (multiplication result)
01 WS-SCORE-ADJUSTED PIC S9(7)V9(4) COMP-3 VALUE 0.
*> Difficulty bonus coefficient (1.1500)
01 WS-DIFFICULTY-FACTOR PIC S9(1)V9(4) COMP-3 VALUE 1.1500.
*> Total budget score
01 WS-BUDGET-TOTAL PIC S9(9)V9(4) COMP-3 VALUE 0.
*> Average budget score
01 WS-BUDGET-AVG PIC S9(7)V9(4) COMP-3 VALUE 0.
*> Overflow test variable (5-digit integer only)
01 WS-OVERFLOW-TEST PIC S9(5) COMP-3 VALUE 99999.
*> -----------------------------------------------
*> For output (edit PIC) — MOVE COMP-3 to DISPLAY format for formatting
*> -----------------------------------------------
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 — Investigation Score Analysis Report".
DISPLAY "====================================".
DISPLAY " ".
*> -----------------------------------------------
*> ADD / SUBTRACT — Aggregate investigation scores
*> Addition between COMP-3 variables runs as fast internal arithmetic
*> -----------------------------------------------
DISPLAY "[ ADD — Investigation Score Total (COMP-3 addition) ]".
*> Add each person's score in sequence
ADD WS-SCORE-LIGHT TO WS-SCORE-TOTAL.
ADD WS-SCORE-L TO WS-SCORE-TOTAL.
ADD WS-SCORE-NEAR TO WS-SCORE-TOTAL.
*> MOVE COMP-3 variables to edit PIC for formatted display
MOVE WS-SCORE-LIGHT TO WS-OUT-SCORE.
DISPLAY " Light Yagami investigation score: " WS-OUT-SCORE.
MOVE WS-SCORE-L TO WS-OUT-SCORE.
DISPLAY " L Lawliet investigation score: " WS-OUT-SCORE.
MOVE WS-SCORE-NEAR TO WS-OUT-SCORE.
DISPLAY " Near investigation score: " WS-OUT-SCORE.
MOVE WS-SCORE-TOTAL TO WS-OUT-SCORE.
DISPLAY " Total : " WS-OUT-SCORE.
DISPLAY " ".
*> -----------------------------------------------
*> COMPUTE ROUNDED — Average investigation score (with rounding)
*> ROUNDED is used when the fractional part exceeds precision
*> -----------------------------------------------
DISPLAY "[ COMPUTE ROUNDED — Average Investigation Score ]".
*> Calculate the average of 3 investigators (round remainder after division)
COMPUTE WS-SCORE-AVG ROUNDED = WS-SCORE-TOTAL / 3.
MOVE WS-SCORE-AVG TO WS-OUT-AVG.
DISPLAY " Average investigation score (ROUNDED): " WS-OUT-AVG.
DISPLAY " ".
*> -----------------------------------------------
*> MULTIPLY — Adjusted value with difficulty coefficient
*> GIVING clause preserves the original variable while storing result in another
*> -----------------------------------------------
DISPLAY "[ MULTIPLY GIVING ROUNDED — Difficulty-adjusted score (L Lawliet) ]".
*> Apply difficulty bonus 1.15 to calculate adjusted investigation score
MULTIPLY WS-DIFFICULTY-FACTOR BY WS-SCORE-L
GIVING WS-SCORE-ADJUSTED ROUNDED.
MOVE WS-SCORE-L TO WS-OUT-SCORE.
DISPLAY " Before adjustment (L Lawliet): " WS-OUT-SCORE.
MOVE WS-SCORE-ADJUSTED TO WS-OUT-ADJUSTED.
DISPLAY " After adjustment : " WS-OUT-ADJUSTED.
DISPLAY " ".
*> -----------------------------------------------
*> High-precision (V9(4)) budget score aggregation
*> Handle 4 fractional digits with COMP-3, maintaining precision through arithmetic
*> -----------------------------------------------
DISPLAY "[ COMPUTE — Budget Score Total and Average (4-decimal COMP-3) ]".
*> Sum the budget scores
COMPUTE WS-BUDGET-TOTAL =
WS-BUDGET-LIGHT + WS-BUDGET-L + WS-BUDGET-MISA.
*> Calculate the average of 3 (round digits beyond 4th decimal place with ROUNDED)
COMPUTE WS-BUDGET-AVG ROUNDED = WS-BUDGET-TOTAL / 3.
MOVE WS-BUDGET-LIGHT TO WS-OUT-BUDGET.
DISPLAY " Light Yagami budget score: " WS-OUT-BUDGET.
MOVE WS-BUDGET-L TO WS-OUT-BUDGET.
DISPLAY " L Lawliet budget score: " WS-OUT-BUDGET.
MOVE WS-BUDGET-MISA TO WS-OUT-BUDGET.
DISPLAY " Misa Amane budget score: " WS-OUT-BUDGET.
MOVE WS-BUDGET-AVG TO WS-OUT-BUDGET-AVG.
DISPLAY " Average of 3 : " WS-OUT-BUDGET-AVG.
DISPLAY " ".
*> -----------------------------------------------
*> ON SIZE ERROR — Overflow detection
*> Attempt to store 99999 squared (9999800001) in a PIC S9(5) variable
*> -----------------------------------------------
DISPLAY "[ ON SIZE ERROR — COMP-3 overflow detection ]".
DISPLAY " Test variable (PIC S9(5) COMP-3) initial value: 99999".
COMPUTE WS-OVERFLOW-TEST = WS-OVERFLOW-TEST * WS-OVERFLOW-TEST
ON SIZE ERROR
DISPLAY " Overflow detected! The variable value was not changed."
NOT ON SIZE ERROR
DISPLAY " Calculation succeeded: " WS-OVERFLOW-TEST
END-COMPUTE.
DISPLAY " ".
DISPLAY "====================================".
DISPLAY " Kira investigation score analysis complete.".
DISPLAY "====================================".
STOP RUN.
cobc -free -x deathnote_comp3.cbl && ./deathnote_comp3 ==================================== DEATH NOTE — Investigation Score Analysis Report ==================================== [ ADD — Investigation Score Total (COMP-3 addition) ] Light Yagami investigation score: 98.50 L Lawliet investigation score: 99.90 Near investigation score: 95.30 Total : 293.70 [ COMPUTE ROUNDED — Average Investigation Score ] Average investigation score (ROUNDED): 97.90 [ MULTIPLY GIVING ROUNDED — Difficulty-adjusted score (L Lawliet) ] Before adjustment (L Lawliet): 99.90 After adjustment : 114.8850 [ COMPUTE — Budget Score Total and Average (4-decimal COMP-3) ] Light Yagami budget score: 5000.0000 L Lawliet budget score: 8500.0000 Misa Amane budget score: 3200.5000 Average of 3 : 5566.8333 [ ON SIZE ERROR — COMP-3 overflow detection ] Test variable (PIC S9(5) COMP-3) initial value: 99999 Overflow detected! The variable value was not changed. ==================================== Kira investigation score analysis complete. ====================================
Overview
In COBOL, COMP-3 (PACKED-DECIMAL) is an internal representation format that packs two decimal digits into one byte. While the normal DISPLAY format uses one byte per digit, COMP-3 stores an n-digit number in (n + 1) / 2 bytes, greatly improving memory efficiency. Furthermore, arithmetic maintains decimal precision as-is, so rounding errors that occur with floating-point numbers (COMP-1/COMP-2) do not arise. This is why COMP-3 has been used for decades in financial, insurance, and tax systems. When declaring, it is recommended to include the sign indicator S as in PIC S9(n)V9(m) COMP-3 (without it, negative results cannot be stored, causing arithmetic errors). Use the ROUNDED clause for rounding after arithmetic, and combine it with the ON SIZE ERROR clause to detect overflow. For screen output, MOVE the COMP-3 variable to an edit PIC variable (such as ZZZ9.99) before using DISPLAY for a readable format. For the basics of numeric PIC clauses, see PIC clause (numeric type). For arithmetic details with COMPUTE statements, see COMPUTE.
Common Mistakes
Mistake 1: COMP-3 byte size rounds up to the nearest byte even for odd digit counts
COMP-3 stores two digits per byte, with the last byte holding the final digit and the sign. PIC S9(5) COMP-3 has 5 digits, so it uses 3 bytes internally ((5 + 1) / 2 = 3). Even if you increase the digit count, the byte count is calculated by rounding up.
*> COMP-3 byte count is calculated as (n + 1) / 2
*> PIC S9(5) COMP-3 — 5 digits → (5+1)/2 = 3 bytes
*> PIC S9(7) COMP-3 — 7 digits → (7+1)/2 = 4 bytes
*> PIC S9(4) COMP-3 — 4 digits → (4+1)/2 = 2.5 → 3 bytes (rounded up)
*> Checking byte efficiency with Light Yagami's investigation analysis scores
01 WS-SCORE-5DIG PIC S9(5) COMP-3 VALUE 12345. *> 3 bytes
01 WS-SCORE-6DIG PIC S9(6) COMP-3 VALUE 123456. *> 4 bytes (same byte count as 5 digits... wait, different)
PROCEDURE DIVISION.
DISPLAY "5-digit score: " WS-SCORE-5DIG.
DISPLAY "6-digit score: " WS-SCORE-6DIG.
STOP RUN.
Just as L Lawliet grasps accurate information, estimate COMP-3 byte counts in advance using the formula (n + 1) / 2. Be aware that 6 digits and 5 digits use different byte counts when declaring.
Mistake 2: Displaying a variable with V (decimal point) directly shows no decimal point
When you DISPLAY a variable declared with V (implied decimal point) such as PIC S9(5)V99 COMP-3 directly, the decimal point is not shown. This is because V only indicates the internal position and has no effect on display.
*> NG: Even with V, displaying directly shows no decimal point
01 WS-SCORE PIC S9(5)V99 COMP-3 VALUE 98.50.
PROCEDURE DIVISION.
DISPLAY "Near's score: " WS-SCORE.
*> Result is displayed as "009850" with no decimal point
STOP RUN.
Just as Misa Amane insists on a visible style, when you need to display with a decimal point, MOVE to an edit PIC variable (such as ZZ9.99) and then DISPLAY.
*> OK: MOVE to an edit PIC variable, then 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's score: " WS-SCORE-DISP.
*> Result: " 98.50" displays correctly
STOP RUN.
Mistake 3: Precision beyond the PIC digit count is truncated after arithmetic
When the result of arithmetic exceeds the digit count or precision defined in the destination variable's PIC clause, the excess is truncated. Without the ROUNDED clause, no rounding occurs either.
*> NG: If the division result exceeds PIC precision, the fractional part is truncated
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... digits from the 3rd decimal place on are truncated
MOVE WS-AVG-NG TO WS-OUT-AVG.
DISPLAY "Average (truncated): " WS-OUT-AVG.
STOP RUN.
Just as Light Yagami builds a perfect plan, for arithmetic requiring precision, either use the ROUNDED clause for rounding or make the destination variable's fractional digit count large enough in advance.
*> OK: Use the ROUNDED clause to round
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 "Average (ROUNDED): " WS-OUT-AVG.
*> Result: " 97.90" displays correctly
STOP RUN.
If you find any errors or copyright issues, please contact us.