COMP, COMP-3 and Packed Decimal

COBOL GnuCOBOL 3.1.2 Β· βœ“ verified by execution on 2026-08-16

When handling financial systems or anything requiring precise decimal calculations, COBOL has been the gold standard for over half a century. While modern programming languages often struggle with the inherent inaccuracies of binary floating-point numbers (like how 0.1 + 0.2 often evaluates to 0.30000000000000004 in languages like JavaScript or Python), COBOL uses packed decimal arithmetic to guarantee exact precision.

In COBOL, you can specify exactly how numbers are stored in memory using the USAGE clause. The most critical format for financial calculations is COMP-3, also known as PACKED-DECIMAL.

What is COMP-3?

By default, COBOL variables use USAGE DISPLAY. In a DISPLAY format, each digit of a number takes up one full byte (8 bits) of memory. This is easy for a human to read if printed directly, but it wastes memory and is inefficient for mathematical operations.

COMP-3 (Computational-3) stores data as β€œpacked decimal”. In this format, each digit takes up only half a byte (a 4-bit nibble). This allows you to store two decimal digits per byte, significantly compressing the data and aligning perfectly with mainframe hardware instructions designed for rapid decimal arithmetic.

The final byte of a COMP-3 field contains the last digit of the number and a 4-bit sign indicator (positive or negative).

Here is how you define a COMP-3 variable:

cobol βœ“ verified output
       IDENTIFICATION DIVISION.
       PROGRAM-ID. Comp3Def.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  NUM-COMP3 PIC S9(5)V99 COMP-3 VALUE 123.45.
       PROCEDURE DIVISION.
           IF NUM-COMP3 > 100
               DISPLAY 'OK'
           END-IF.
           STOP RUN.
Output
OK

Note: The official GnuCOBOL documentation confirms that PACKED-DECIMAL is an exact synonym for COMP-3. You can use them interchangeably:

cobol βœ“ verified output
       IDENTIFICATION DIVISION.
       PROGRAM-ID. PackedDef.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  NUM-PACKED PIC S9(5)V99 PACKED-DECIMAL VALUE 123.45.
       PROCEDURE DIVISION.
           IF NUM-PACKED > 100
               DISPLAY 'OK'
           END-IF.
           STOP RUN.
Output
OK

Mathematical Precision

Because COMP-3 stores exact decimal digits rather than attempting to encode them as fractions of base-2 (which causes floating-point errors), mathematical operations are perfectly precise:

cobol βœ“ verified output
       IDENTIFICATION DIVISION.
       PROGRAM-ID. Comp3Prec.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  TOTAL PIC S9(9)V99 COMP-3 VALUE 0.
       PROCEDURE DIVISION.
           ADD 0.1 TO TOTAL.
           ADD 0.2 TO TOTAL.
           IF TOTAL = 0.3
               DISPLAY 'EXACT'
           END-IF.
           STOP RUN.
Output
EXACT

Displaying COMP-3 Data

Because COMP-3 stores data in packed binary format (not as readable text characters), you cannot DISPLAY a COMP-3 field directly and expect to see a readable number. It will print binary gibberish to the terminal.

To print a COMP-3 value, you must first MOVE it to a standard DISPLAY variable. COBOL handles the unpacking conversion automatically during the MOVE:

cobol βœ“ verified output
       IDENTIFICATION DIVISION.
       PROGRAM-ID. Comp3Disp.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  NUM-COMP3 PIC S9(5)V99 COMP-3 VALUE 123.45.
       01  NUM-DISP  PIC -9(5).99.
       PROCEDURE DIVISION.
           MOVE NUM-COMP3 TO NUM-DISP.
           DISPLAY NUM-DISP.
           STOP RUN.
Output
 00123.45

Visualizing the Memory Layout

USAGE DISPLAY (PIC 999) 1 (Byte) 2 (Byte) 3 (Byte) USAGE COMP-3 (PIC 999) 0 1 2 3 + Packed into 2.5 Bytes (5 Nibbles)

Predict the Output

To reinforce the necessity of formatting, predict what happens when we manipulate packed decimal data but then re-assign it over standard text strings without a numeric conversion move:

Predict the output cobol

Read the code. What exactly will it print? Commit to an answer before you look.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. Comp3Math.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  TOTAL PIC S9(9)V99 COMP-3 VALUE 0.
       PROCEDURE DIVISION.
           ADD 0.1 TO TOTAL.
           ADD 0.2 TO TOTAL.
           IF TOTAL = 0.3
               DISPLAY 1
           ELSE
               DISPLAY 0
           END-IF.
           STOP RUN.
Output
1

Unlike floating-point languages where 0.1 + 0.2 = 0.30000000000000004, COMP-3 uses exact decimal encoding, so it is strictly equal to 0.3.

Check yourself

What does the COMP-3 format do?

Reveal answer

Stores data as exact decimal digits, two per byte. β€” COMP-3 stores data as packed decimal, placing two decimal digits in each byte (except the final byte which holds the sign), preventing binary floating point precision loss.

Can you directly print a COMP-3 variable?

Reveal answer

No, it outputs unprintable binary characters and must be moved to a DISPLAY field first. β€” Because COMP-3 is a binary format (packed decimal), printing it directly displays raw bytes. You must first MOVE it to a formatted USAGE DISPLAY (PIC -9.99) variable to print it.

What is the difference between COMP-3 and PACKED-DECIMAL?

Reveal answer

There is no difference; they are exact synonyms in modern COBOL. β€” Both COMP-3 and PACKED-DECIMAL instruct the compiler to use packed decimal storage and are treated identically by modern COBOL compilers.

Challenges

🐞 Bug Hunt +50 XP

A developer believed that COBOL requires binary floating-point (`COMP-1`) for fast decimal math. But a rounding error has crept into the total balance! Change the definition of `TOTAL-BALANCE` to use exact packed decimal so precision is preserved.

This code runs. It just does the wrong thing. Read it, find the defect, fix it β€” the tests below decide when you are right.

cobol βœ“ solution verified at build time

COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the fixed code should be, then open the solution and compare. The expected output below is real β€” it came from compiling the solution with GnuCOBOL when this page was built.

  • Test 1 β€” expects "Total: 12345678.99\n"
Show solution (0 XP)
       IDENTIFICATION DIVISION.
       PROGRAM-ID. BugHuntFloat.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  TOTAL-BALANCE   PIC 9(8)V99 COMP-3 VALUE 12345678.99.
       01  DISPLAY-BALANCE PIC 9(8).99.
       PROCEDURE DIVISION.
           MOVE TOTAL-BALANCE TO DISPLAY-BALANCE.
           DISPLAY 'Total: ' DISPLAY-BALANCE.
           STOP RUN.

Challenge 2 +50 XP

Convert the SALES-AMOUNT (which is in COMP-3) into the PRINT-AMOUNT variable so it can be displayed nicely.

cobol βœ“ solution verified at build time

COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the fixed code should be, then open the solution and compare. The expected output below is real β€” it came from compiling the solution with GnuCOBOL when this page was built.

  • Test 1 β€” expects " 00456.78\n"
Show solution (0 XP)
       IDENTIFICATION DIVISION.
       PROGRAM-ID. CComp3Disp.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  SALES-AMOUNT PIC S9(5)V99 COMP-3 VALUE 456.78.
       01  PRINT-AMOUNT PIC -9(5).99.
       PROCEDURE DIVISION.
           MOVE SALES-AMOUNT TO PRINT-AMOUNT.
           DISPLAY PRINT-AMOUNT.
           STOP RUN.

Challenge 3 +50 XP

Add the TAX to the TOTAL using exact COMP-3 decimal arithmetic, then move it to PRINT-TOTAL and display it.

cobol βœ“ solution verified at build time

COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the fixed code should be, then open the solution and compare. The expected output below is real β€” it came from compiling the solution with GnuCOBOL when this page was built.

  • Test 1 β€” expects " 00115.50\n"
Show solution (0 XP)
       IDENTIFICATION DIVISION.
       PROGRAM-ID. CComp3Math.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  TOTAL PIC S9(5)V99 COMP-3 VALUE 100.00.
       01  TAX   PIC S9(5)V99 COMP-3 VALUE 15.50.
       01  PRINT-TOTAL PIC -9(5).99.
       PROCEDURE DIVISION.
           ADD TAX TO TOTAL.
           MOVE TOTAL TO PRINT-TOTAL.
           DISPLAY PRINT-TOTAL.
           STOP RUN.