Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

COBOL  Module 3 – Numbers in storage, money arithmetic and dates

USAGE: zoned, packed decimal (COMP-3) and binary

How COBOL stores numbers as DISPLAY, COMP-3, COMP, COMP-5 and floating point: the bytes of each, the sign half-bytes, dialect sizes and which USAGE to choose.

  • Intermediate
  • 15 minutes
  • Examples run with GnuCOBOL 3.2 and Python 3.14.8
  • By MySmartCoPilot
Free lesson, Pro answers: 15 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Predict the storage size of DISPLAY, COMP-3, COMP, COMP-5, COMP-1 and COMP-2 items
  • Read the bytes of zoned and packed decimal values, including their sign half-bytes
  • Explain how binary sizes and byte order differ between GnuCOBOL dialects and IBM Enterprise COBOL
  • Choose a USAGE for counters, money, files and interfaces to other languages

Before you start

What you’ll learn · Before you start

What you will learn

  • Predict the storage size of DISPLAY, COMP-3, COMP, COMP-5, COMP-1 and COMP-2 items
  • Read the bytes of zoned and packed decimal values, including their sign half-bytes
  • Explain how binary sizes and byte order differ between GnuCOBOL dialects and IBM Enterprise COBOL
  • Choose a USAGE for counters, money, files and interfaces to other languages

Before you start

On this page

The value -1234 takes 4 bytes in USAGE DISPLAY, 3 in packed decimal and 2 in binary, and the three share no byte: 31323374, 01234D and FB2E. A program that reads a field with the wrong USAGE gets a wrong number and no error, and a copybook built in another dialect can describe a record one byte shorter than the file it reads.

Below you will size an item of every USAGE before you compile it, read zoned and packed decimal bytes with their sign half-bytes, see where GnuCOBOL’s dialects and IBM Enterprise COBOL lay out binary items differently, and choose a USAGE for counters, money, files and calls to other languages.

USAGE decides how many bytes a number takes, and which bytes

The USAGE clause: The clause that says how an item's value is stored: DISPLAY as characters, PACKED-DECIMAL or COMP-3 as packed digits, BINARY, COMP or COMP-5 as binary integers, and COMP-1 or COMP-2 as floating point. says how the value of an item is kept in storage. An item that names none is USAGE DISPLAY, the characters of the lessons before this one. This program puts one value, -1234, into six items that differ only in USAGE, then a nine-digit amount into three, and prints the size of each from BYTE-LENGTH and its bytes from HEX-OF:

storage.cob: one value under six USAGEs COB · storage.cob
       IDENTIFICATION DIVISION.
       PROGRAM-ID. STORAGE.
      * One value, -1234, under six USAGEs (PIC S9999 for the four
      * that take a PICTURE), then the nine-digit amount PIC S9(7)V99
      * under three of them: the size of each item from BYTE-LENGTH
      * and its bytes from HEX-OF.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  N-DISPLAY   PIC S9999         VALUE -1234.
       01  N-PACKED    PIC S9999 COMP-3  VALUE -1234.
       01  N-BINARY    PIC S9999 COMP    VALUE -1234.
       01  N-NATIVE    PIC S9999 COMP-5  VALUE -1234.
       01  N-FLOAT-1   COMP-1            VALUE -1234.
       01  N-FLOAT-2   COMP-2            VALUE -1234.
       01  A-DISPLAY   PIC S9(7)V99         VALUE 1234567.89.
       01  A-PACKED    PIC S9(7)V99 COMP-3  VALUE 1234567.89.
       01  A-BINARY    PIC S9(7)V99 COMP    VALUE 1234567.89.
       PROCEDURE DIVISION.
           DISPLAY "-1234 in PIC S9999  bytes  hex"
           DISPLAY "DISPLAY             "
               FUNCTION BYTE-LENGTH(N-DISPLAY) "      "
               FUNCTION HEX-OF(N-DISPLAY)
           DISPLAY "COMP-3              "
               FUNCTION BYTE-LENGTH(N-PACKED) "      "
               FUNCTION HEX-OF(N-PACKED)
           DISPLAY "COMP                "
               FUNCTION BYTE-LENGTH(N-BINARY) "      "
               FUNCTION HEX-OF(N-BINARY)
           DISPLAY "COMP-5              "
               FUNCTION BYTE-LENGTH(N-NATIVE) "      "
               FUNCTION HEX-OF(N-NATIVE)
           DISPLAY "COMP-1, no PICTURE  "
               FUNCTION BYTE-LENGTH(N-FLOAT-1) "      "
               FUNCTION HEX-OF(N-FLOAT-1)
           DISPLAY "COMP-2, no PICTURE  "
               FUNCTION BYTE-LENGTH(N-FLOAT-2) "      "
               FUNCTION HEX-OF(N-FLOAT-2)
           DISPLAY " "
           DISPLAY "1234567.89 in PIC S9(7)V99"
           DISPLAY "DISPLAY             "
               FUNCTION BYTE-LENGTH(A-DISPLAY) "      "
               FUNCTION HEX-OF(A-DISPLAY)
           DISPLAY "COMP-3              "
               FUNCTION BYTE-LENGTH(A-PACKED) "      "
               FUNCTION HEX-OF(A-PACKED)
           DISPLAY "COMP                "
               FUNCTION BYTE-LENGTH(A-BINARY) "      "
               FUNCTION HEX-OF(A-BINARY)
           STOP RUN.
The size and the bytes of each item Python · storage_session.py
from session import files, run

# Sizes and bytes of one value under six USAGEs, built with GnuCOBOL's default dialect.
files("storage.cob")
run("""
cobc -x storage.cob
./storage
""")

Output

$ cobc -x storage.cob
$ ./storage
-1234 in PIC S9999  bytes  hex
DISPLAY             4      31323374
COMP-3              3      01234D
COMP                2      FB2E
COMP-5              2      2EFB
COMP-1, no PICTURE  4      00409AC4
COMP-2, no PICTURE  8      00000000004893C0

1234567.89 in PIC S9(7)V99
DISPLAY             9      313233343536373839
COMP-3              5      123456789C
COMP                4      075BCD15

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 storage_session.py

Read the sizes first. DISPLAY spends a byte on each digit, 4 bytes, and packed decimal, COMP-3, fits two digits into a byte, 3 bytes. COMP keeps the number as a base-2 integer in 2 bytes, and so does COMP-5. COMP-1 and COMP-2 take no PICTURE at all: they are floating point, 4 and 8 bytes whatever the value. The nine-digit amount repeats the pattern at a larger size, 9, 5 and 4 bytes.

USAGE Also written PIC S9999 PIC S9(7)V99 Size rule
DISPLAY the default 4 bytes 9 bytes one byte a digit
COMP-3 PACKED-DECIMAL 3 5 two digits a byte, plus a sign
COMP BINARY, COMP-4 2 4 2, 4 or 8 bytes by the digits
COMP-5 none 2 4 as COMP
COMP-1, COMP-2 no PICTURE 4, 8 4, 8 floating point

Then compare the bytes with IBM’s table of internal representations, which gives the same value on z/OS. Packed decimal and binary match byte for byte, X’01234D’ and X’FB2E’. The others do not. GnuCOBOL wrote DISPLAY as ASCII characters, 31323374, where z/OS keeps EBCDIC ones, F1F2F3D4; COMP-5 came out as 2EFB, the two bytes of the COMP value in the other order; and COMP-1 and COMP-2 are IEEE floating point here, 00409AC4 for COMP-1, where IBM’s table shows hexadecimal floating point, C34D2000. The next three sections take those differences one at a time.

Size two items before you print them

Add 01 N-TEN PIC S9(10) COMP VALUE 1. and 01 N-ODD PIC S9(5) COMP-3 VALUE 1. to storage.cob with a DISPLAY of each BYTE-LENGTH. Write down your two sizes, then build it with cobc -x storage.cob && ./storage: 8 bytes for ten binary digits and 3 for five packed ones.

Checkpoint

Check: Bytes for each USAGE

  1. One question How many bytes does PIC S9(7)V99 COMP-3 take?

    Type a number.

    A hint

    Count the digits, add one half-byte for the sign, and turn half-bytes into bytes.

    Show the answer: One question

    Answer: 5 bytes

    Nine digits and a sign are ten half-bytes, five bytes: the session printed 5 and X'123456789C'. The same PICTURE took 9 bytes in DISPLAY and 4 in COMP.

Zoned decimal keeps a digit in each byte and the sign in the last zone

A DISPLAY number is called zoned decimal: A number in USAGE DISPLAY: one digit a byte, kept as a character, with the sign of a signed item in the zone, the left half-byte, of its last byte unless SIGN ... SEPARATE gives the sign a byte of its own., after the two halves of each of its bytes. Written in hexadecimal, a byte is two half-byte: Four bits, written as one hexadecimal digit. A byte is two half-bytes, so X'4D' has the half-bytes 4 and D; packed decimal keeps one digit or the sign in each.: the character 1 is X’31’ in ASCII, a zone of 3 and a digit of 1, and X’F1’ in EBCDIC, a zone of F. A signed item has no byte for its sign, so the sign takes the zone of the last digit. This program stores four values in PIC S9999, prints the character each signed digit becomes, then reads the text 123M back as a number. The session builds it twice, with GnuCOBOL’s own convention for ASCII and with -fsign=EBCDIC:

zoned.cob: four signed values in PIC S9999 COB · zoned.cob
       IDENTIFICATION DIVISION.
       PROGRAM-ID. ZONED.
      * Signed zoned decimal: four values in PIC S9999 as bytes and as
      * the characters a text editor shows, the character of each
      * signed digit, then the text 123M read as a number.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  AMT          PIC S9999.
       01  AMT-TEXT     REDEFINES AMT PIC X(4).
       01  ONE-DIGIT    PIC S9.
       01  ONE-TEXT     REDEFINES ONE-DIGIT PIC X.
       01  D            PIC 99.
       01  PLUS-ROW     PIC X(10).
       01  MINUS-ROW    PIC X(9).
       01  AMT-OUT      PIC -9999.
       PROCEDURE DIVISION.
           MOVE 1234 TO AMT
           PERFORM SHOW-AMT
           MOVE -1234 TO AMT
           PERFORM SHOW-AMT
           MOVE 1230 TO AMT
           PERFORM SHOW-AMT
           MOVE -1230 TO AMT
           PERFORM SHOW-AMT
           PERFORM VARYING D FROM 0 BY 1 UNTIL D > 9
               MOVE D TO ONE-DIGIT
               MOVE ONE-TEXT TO PLUS-ROW(D + 1:1)
           END-PERFORM
           PERFORM VARYING D FROM 1 BY 1 UNTIL D > 9
               COMPUTE ONE-DIGIT = 0 - D
               MOVE ONE-TEXT TO MINUS-ROW(D:1)
           END-PERFORM
           DISPLAY "+0 to +9  " PLUS-ROW
           DISPLAY "-1 to -9  " MINUS-ROW
           MOVE "123M" TO AMT-TEXT
           MOVE AMT TO AMT-OUT
           DISPLAY "123M as a number  " AMT-OUT
           STOP RUN.
       SHOW-AMT.
           DISPLAY FUNCTION HEX-OF(AMT) "  [" AMT-TEXT "]".
The sign in the last byte, two ways Python · zoned_session.py
from session import files, run

# The same program built twice: with GnuCOBOL's own sign convention for ASCII, then with -fsign=EBCDIC, which stores
# the sign the way an EBCDIC record reads once its bytes are translated to ASCII.
files("zoned.cob")
run("""
cobc -x zoned.cob
./zoned
cobc -x -fsign=EBCDIC -o zoned-ebcdic zoned.cob
./zoned-ebcdic
""")

Output

$ cobc -x zoned.cob
$ ./zoned
31323334  [1234]
31323374  [123t]
31323330  [1230]
31323370  [123p]
+0 to +9  0123456789
-1 to -9  qrstuvwxy
123M as a number   1230
$ cobc -x -fsign=EBCDIC -o zoned-ebcdic zoned.cob
$ ./zoned-ebcdic
31323344  [123D]
3132334D  [123M]
3132337B  [123{]
3132337D  [123}]
+0 to +9  {ABCDEFGHI
-1 to -9  JKLMNOPQR
123M as a number  -1234

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 zoned_session.py

Only the last byte ever changed. In the default build a positive value kept the plain digit, X’34’, and a negative one got the zone 7, X’74’, which a text editor shows as t, so -1234 read 123t. With -fsign=EBCDIC the last byte is the character that the mainframe’s signed digit becomes when a record is translated from EBCDIC to ASCII: an opening brace for +0 and a closing one for -0, A to I for the positive digits 1 to 9 and J to R for the negative ones, so -1234 read 123M and -1230 read 123}. A sign kept in the zone of a digit is called an overpunch: A sign kept in the zone of a number's last digit instead of a byte of its own. An EBCDIC record translated to ASCII shows it as a letter or a brace, so -1234 reads 123M.. Step through the bytes of -1234:

Interactive · stage by stage -1234 in PIC S9999, byte by byte Step down the column to see where the sign of a zoned decimal item goes, in GnuCOBOL and on z/OS.
-1234 in PIC S9999, byte by byte, step 6 of 6. Showing Four digits, four bytes, Zone and digit halves, Sign in the last zone, GnuCOBOL default: X'74', -fsign=EBCDIC: X'4D', z/OS: F1 F2 F3 D4. In focus: z/OS: F1 F2 F3 D4.Four digits, four bytesthe characters 1, 2, 3, 4Zone and digit halvesX'31' is zone 3, digit 1Sign in the last zoneonly the 4 changesGnuCOBOL default: X'74'zone 7 for minus: 123t-fsign=EBCDIC: X'4D'the M of EBCDIC X'D4'z/OS: F1 F2 F3 D4zones F, the last zone D

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. The digits. In USAGE DISPLAY each digit is one byte that holds the digit as a character, so PIC S9999 is four bytes for 1, 2, 3 and 4. The S adds no byte.
  2. Two halves. A byte is two half-bytes, written as two hexadecimal digits. In ASCII the character 1 is X'31': the left half, the zone, is 3, and the right half is the digit 1.
  3. The sign. A signed zoned item has no byte for its sign. The sign takes the zone of the last byte instead, so only the byte that holds the 4 changes when the value is negative.
  4. GnuCOBOL's default. GnuCOBOL's own convention for ASCII sets that zone to 7 for a negative value: the last byte is X'74', which a text editor shows as t, so the item reads 123t.
  5. The EBCDIC convention. Built with -fsign=EBCDIC, GnuCOBOL stores X'4D', the character M. That is the mainframe's signed byte X'D4' after a record is translated from EBCDIC to ASCII, and the same build reads 123M back as -1234.
  6. On z/OS. On z/OS the digits are EBCDIC characters, X'F1' to X'F4', and the zone of the last byte is D for a negative value and C for a positive one: IBM's table gives F1 F2 F3 D4 for -1234.

Treating 123M in a translated file as damage

Wrong: removing the letter at the end of each amount in a file that came from z/OS as text. The default build’s last line shows what it made of 123M: 1230, positive, without a word. Right: describe the field as signed zoned decimal and build with -fsign=EBCDIC, which read the same bytes as -1234, or, better, have the file sent with SIGN TRAILING SEPARATE or edited amounts.

On z/OS itself the digits are EBCDIC characters, X’F1’ to X’F9’, and the zone of the last byte holds the sign: IBM’s table gives F1 F2 F3 D4 for -1234. IBM’s guide lists X’C’, X’A’, X’E’ and X’F’ as valid positive signs and X’D’ and X’B’ as negative ones, and its compiler writes the preferred signs itself, C for positive, D for negative and F for unsigned data.

Key idea

A zoned decimal item is one character for each digit, and its sign lives in the zone of the last byte: read that byte, and the sign convention of the file, before you trust the amount.

Checkpoint

Check: Zoned decimal and its sign zone

  1. One question Built with -fsign=EBCDIC, how does -1230 in PIC S9999 read as text?

    Choose one answer.

    Show the answer: One question

    Answer: 123}

    The session printed 3132337D, 123}, for -1230 and 3132337B, 123{, for +1230. Only the last byte carries the sign.

Packed decimal keeps two digits in a byte and the sign in the last half

packed decimal: USAGE PACKED-DECIMAL or COMP-3: two decimal digits in each byte and a sign in the last half-byte, C for positive, D for negative and F for unsigned, so PIC S9(5) takes 3 bytes., USAGE COMP-3 or PACKED-DECIMAL, drops the zones. Each digit takes one half-byte, and one more half-byte at the right holds the sign: C for positive, D for negative and F for an unsigned item, the same in GnuCOBOL and on z/OS. Seven items show the rule:

packed.cob: seven packed items COB · packed.cob
       IDENTIFICATION DIVISION.
       PROGRAM-ID. PACKED.
      * Packed decimal: two digits a byte and the sign in the last
      * half-byte. Each line shows the PICTURE, the size and the bytes.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  P-AMOUNT    PIC S9(3)V99 COMP-3 VALUE -42.50.
       01  P-UNSIGNED  PIC 9(5)     COMP-3 VALUE 12345.
       01  P-ODD       PIC S9(5)    COMP-3 VALUE 12345.
       01  P-EVEN      PIC S9(4)    COMP-3 VALUE 1234.
       01  P-BALANCE   PIC S9(7)V99 COMP-3 VALUE 1234567.89.
       01  P-ONE       PIC S9       COMP-3 VALUE 7.
       01  P-TWO       PIC S99      COMP-3 VALUE 42.
       PROCEDURE DIVISION.
           DISPLAY "S9(3)V99 -42.50     "
               FUNCTION BYTE-LENGTH(P-AMOUNT) "  "
               FUNCTION HEX-OF(P-AMOUNT)
           DISPLAY "9(5)     12345      "
               FUNCTION BYTE-LENGTH(P-UNSIGNED) "  "
               FUNCTION HEX-OF(P-UNSIGNED)
           DISPLAY "S9(5)    12345      "
               FUNCTION BYTE-LENGTH(P-ODD) "  "
               FUNCTION HEX-OF(P-ODD)
           DISPLAY "S9(4)    1234       "
               FUNCTION BYTE-LENGTH(P-EVEN) "  "
               FUNCTION HEX-OF(P-EVEN)
           DISPLAY "S9(7)V99 1234567.89 "
               FUNCTION BYTE-LENGTH(P-BALANCE) "  "
               FUNCTION HEX-OF(P-BALANCE)
           DISPLAY "S9       7          "
               FUNCTION BYTE-LENGTH(P-ONE) "  "
               FUNCTION HEX-OF(P-ONE)
           DISPLAY "S99      42         "
               FUNCTION BYTE-LENGTH(P-TWO) "  "
               FUNCTION HEX-OF(P-TWO)
           STOP RUN.
Sizes and bytes of packed items Python · packed_session.py
from session import files, run

# Seven packed-decimal items: their sizes and their bytes.
files("packed.cob")
run("""
cobc -x packed.cob
./packed
""")

Output

$ cobc -x packed.cob
$ ./packed
S9(3)V99 -42.50     3  04250D
9(5)     12345      3  12345F
S9(5)    12345      3  12345C
S9(4)    1234       3  01234C
S9(7)V99 1234567.89 5  123456789C
S9       7          1  7C
S99      42         2  042C

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 packed_session.py

-42.50 in PIC S9(3)V99 is X’04250D’: the digits 0 4 2 5 0 read straight off the hexadecimal, then D for minus, and no point, because the V stores nothing. 12345 is X’12345F’ without an S and X’12345C’ with one. To size an item, count its digits and one half-byte for the sign, then round up to whole bytes: 3 bytes for 5 digits and 5 bytes for the 9 digits of S9(7)V99, as the run printed. Step through the packing of -42.50:

Interactive · stage by stage -42.50 packed into PIC S9(3)V99 COMP-3 Step down the column to see how five digits and a sign become three bytes.
-42.50 packed into PIC S9(3)V99 COMP-3, step 5 of 5. Showing Five digits: 0 4 2 5 0, One sign half-byte, Pair the half-bytes, 3 bytes: X'04250D', Even counts waste a half. In focus: Even counts waste a half.Five digits: 0 4 2 5 0the V is not storedOne sign half-byteD for a negative valuePair the half-bytes04 | 25 | 0D3 bytes: X'04250D'DISPLAY would need 5Even counts waste a half1234 in S9(4): X'01234C'

The drawing shows the whole scene; its 5 steps are listed below.

Every step as text
  1. The digits. PIC S9(3)V99 holds five digits. For -42.50 they are 0, 4, 2, 5 and 0. The leading zero fills the third integer place, and the V marks where the point falls without storing anything.
  2. The sign. Packed decimal keeps every digit in one half-byte and adds one more half-byte after the last digit for the sign. Its value is D for a negative number, C for a positive one and F for an unsigned item.
  3. The pairs. The six half-bytes make three bytes, 0 and 4, 2 and 5, 0 and D. Two digits share every byte except the last, which holds one digit and the sign.
  4. The result. The item is X'04250D', three bytes where USAGE DISPLAY needs five. Read the digits straight off the hexadecimal, then put the point where the PICTURE says: -042.50.
  5. An even digit count. With four digits and a sign there are five half-bytes, so the byte at the left keeps one half spare and fills it with 0: 1234 in PIC S9(4) COMP-3 is X'01234C', the same three bytes that PIC S9(5) uses for one more digit.

Key idea

Packed decimal is the digits in hexadecimal followed by a sign half-byte, C, D or F, so X’04250D’ reads -042.50 once the PICTURE says where the point goes.

S9(4) holding 1234 also took 3 bytes, X’01234C’. With an even number of digits the half-byte at the far left holds no digit and is set to 0, so S9(4) and S9(5) cost the same. IBM’s programming guide advises an odd number of digits for packed items, so that an item fills whole bytes with no half-byte left over, and IBM’s RULES(NOEVENPACK) option warns about every packed item with an even count, because a spare half-byte whose bits are not zero “can lead to an unexpected program behavior”.

Choosing PIC S9(4) COMP-3 to save a byte

Wrong: S9(4) COMP-3 for amounts up to 9999, to keep the field small. It takes 3 bytes, the same as S9(5), and wastes a half-byte. Right: give packed items an odd number of digits, S9(5) here, and the extra digit costs nothing.

Checkpoint

Check: Packed decimal and its sign half-byte

  1. Question 1 of 2 What bytes does PIC S9(5) COMP-3 hold for -7350?

    Choose one answer.

    A hint

    Five digits, then the sign half-byte.

    Show the answer: Question 1 of 2

    Answer: X'07350D'

    Write the digits in hexadecimal, add D for a negative value, and pair the half-bytes: X'07350D'.

  2. Question 2 of 2 How many bytes does PIC S9(6) COMP-3 take?

    Type a number.

    A hint

    Six digits and one sign half-byte.

    Show the answer: Question 2 of 2

    Answer: 4 bytes

    Seven half-bytes round up to four bytes, with the leftmost half spare and set to 0, so PIC S9(7) COMP-3 holds one more digit in the same four bytes. IBM's RULES(NOEVENPACK) warns about such even counts.

Binary sizes follow the dialect, and COMP-5 follows the machine

Binary items, COMP, BINARY or COMP-4, keep the value as a base-2 integer and treat the decimal places of the PICTURE as a scale: 1234567.89 in PIC S9(7)V99 COMP was X’075BCD15’, the integer 123456789. Their size comes from the number of digits, and here the compilers disagree. IBM documents 2 bytes for 1 to 4 digits, 4 for 5 to 9 and 8 for 10 to 18. GnuCOBOL’s default dialect sets binary-size to 1-2-4-8, which gives 1 or 2 digits a single byte. This record of three counters is built both ways:

binary.cob: a record of three binary counters COB · binary.cob
       IDENTIFICATION DIVISION.
       PROGRAM-ID. BINARY-SIZES.
      * Binary items: the size of a record of three COMP counters,
      * then the bytes of 1234 in COMP (big-endian) and in COMP-5
      * (the byte order of the machine that runs the program).
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  BRANCH-COUNTS.
           05  BC-BRANCH    PIC S9(2) COMP VALUE 12.
           05  BC-DAYS      PIC S9(4) COMP VALUE 1234.
           05  BC-ITEMS     PIC S9(9) COMP VALUE 123456789.
       01  N-BINARY         PIC S9(4) COMP   VALUE 1234.
       01  N-NATIVE         PIC S9(4) COMP-5 VALUE 1234.
       PROCEDURE DIVISION.
           DISPLAY "BRANCH-COUNTS  size "
               FUNCTION BYTE-LENGTH(BRANCH-COUNTS) "  "
               FUNCTION HEX-OF(BRANCH-COUNTS)
           DISPLAY "  PIC S9(2)    size "
               FUNCTION BYTE-LENGTH(BC-BRANCH) "  "
               FUNCTION HEX-OF(BC-BRANCH)
           DISPLAY "  PIC S9(4)    size "
               FUNCTION BYTE-LENGTH(BC-DAYS) "  "
               FUNCTION HEX-OF(BC-DAYS)
           DISPLAY "  PIC S9(9)    size "
               FUNCTION BYTE-LENGTH(BC-ITEMS) "  "
               FUNCTION HEX-OF(BC-ITEMS)
           DISPLAY "1234 in COMP   " FUNCTION HEX-OF(N-BINARY)
           DISPLAY "1234 in COMP-5 " FUNCTION HEX-OF(N-NATIVE)
           STOP RUN.
Two dialects, two byte orders, and a COMP-5 amount Python · binary_session.py
from session import files, run

# The binary program built with GnuCOBOL's default dialect and with -std=ibm, then the DISPLAY of a COMP-5 amount.
files("binary.cob", "display5.cob")
run("""
cobc -x -o binary binary.cob
./binary
cobc -x -std=ibm -o binary-ibm binary.cob
./binary-ibm
cobc -x display5.cob
./display5
""")

Output

$ cobc -x -o binary binary.cob
$ ./binary
BRANCH-COUNTS  size 7  0C04D2075BCD15
  PIC S9(2)    size 1  0C
  PIC S9(4)    size 2  04D2
  PIC S9(9)    size 4  075BCD15
1234 in COMP   04D2
1234 in COMP-5 D204
$ cobc -x -std=ibm -o binary-ibm binary.cob
$ ./binary-ibm
BRANCH-COUNTS  size 8  000C04D2075BCD15
  PIC S9(2)    size 2  000C
  PIC S9(4)    size 2  04D2
  PIC S9(9)    size 4  075BCD15
1234 in COMP   04D2
1234 in COMP-5 D204
$ cobc -x display5.cob
$ ./display5
COMP   +0000025000000.00
COMP-5 +00000000002500000000
edited        25,000,000.00

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 binary_session.py

BRANCH-COUNTS was 7 bytes in the default build and 8 with -std=ibm, whose configuration sets binary-size to 2-4-8, because BC-BRANCH, PIC S9(2) COMP, took 1 byte and then 2. Every field after it in a record moves by that byte, so a copybook shared with z/OS is built with -std=ibm, or with -fbinary-size=2-4-8.

Digits in the PICTURE GnuCOBOL default, 1-2-4-8 IBM Enterprise COBOL and -std=ibm, 2-4-8
1 or 2 1 byte 2 bytes
3 or 4 2 bytes 2 bytes
5 to 9 4 bytes 4 bytes
10 to 18 8 bytes 8 bytes

Byte order is the second difference. COMP and BINARY are big-endian: A byte order that stores the most significant byte first, so 1234 in two bytes is X'04D2'. COBOL's BINARY and COMP items use it in GnuCOBOL and on z/OS; COMP-5 takes the order of the machine. in both compilers, the most significant byte first, so 1234 was X’04D2’ in both builds, as in IBM’s table. COMP-5 is native binary, kept in the byte order of the machine that runs the program. This Mac’s arm64 processor is little-endian, so 1234 in COMP-5 was X’D204’, the same two bytes reversed, where IBM’s table shows COMP-5 on z/OS in big-endian order, X’3039’ for 12345. COMP-5 is also not held to its PICTURE: IBM lets it hold values up to the capacity of its bytes, so PIC S9(4) COMP-5 takes -32,768 to 32,767, which the next lesson’s overflow tests rely on. The session’s last program, display5.cob, prints one amount kept in COMP and in COMP-5:

display5.cob: one amount in COMP and in COMP-5 COB · display5.cob
       IDENTIFICATION DIVISION.
       PROGRAM-ID. DISPLAY5.
      * The same amount with two decimal places in COMP and in COMP-5,
      * printed with DISPLAY and through an edited item.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  LIMIT-BIN    PIC S9(13)V99 COMP   VALUE 25000000.00.
       01  LIMIT-NAT    PIC S9(13)V99 COMP-5 VALUE 25000000.00.
       01  LIMIT-OUT    PIC Z,ZZZ,ZZZ,ZZZ,ZZ9.99-.
       PROCEDURE DIVISION.
           DISPLAY "COMP   " LIMIT-BIN
           DISPLAY "COMP-5 " LIMIT-NAT
           MOVE LIMIT-NAT TO LIMIT-OUT
           DISPLAY "edited " LIMIT-OUT
           STOP RUN.

Printing a COMP-5 amount with DISPLAY

Wrong: DISPLAY of a COMP-5 item with decimal places, which GnuCOBOL 3.2 printed as +00000000002500000000 for 25,000,000.00, with no point, while COMP in the same build printed +0000025000000.00. Right: move the item to an edited item first, as display5.cob did, which printed 25,000,000.00.

A layout that crosses from one machine to another therefore pins down both differences: the size of every binary field and the byte order it is written in.

Key idea

Binary sizes depend on the dialect, 1-2-4-8 in GnuCOBOL’s default and 2-4-8 in IBM’s compiler, and COMP-5 bytes depend on the machine: build shared layouts with -std=ibm, and keep COMP-5 for data that stays on one machine.

Checkpoint

Check: Binary sizes and byte order

  1. Question 1 of 2 How many bytes does PIC S9(2) COMP take when GnuCOBOL builds with -std=ibm?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: 2

    binary.cob printed size 1 and X'0C' for BC-BRANCH in the default build, and size 2 and X'000C' with -std=ibm.

  2. Question 2 of 2 What did HEX-OF show for 1234 in PIC S9(4) COMP-5 on this lesson's arm64 Mac?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: X'D204'

    The same value was X'04D2' in COMP and X'D204' in COMP-5: two bytes, in opposite orders.

Choose the USAGE by what the field holds and who reads it

The choice follows from the sizes and bytes above, with one more fact about floating point. COMP-1 and COMP-2 cover a wide range in 4 or 8 bytes but hold most decimal fractions only approximately: Python’s decimal documentation shows 0.1 + 0.1 + 0.1 - 0.3 in binary floating point coming to 5.5511151231257827e-017 instead of zero. IBM’s guide adds the advice for the others: BINARY, signed and with eight digits or fewer, for items used mainly in arithmetic or as subscripts, because binary operations are faster than decimal ones, and PACKED-DECIMAL for items of more than eight digits or used with DISPLAY data. Answer the two questions in the table for a field of your own:

Interactive · answer and compare Which USAGE fits the field? Answer two questions about a field of yours, what it holds and who else reads its bytes. The table marks the USAGEs that fit and says why the others do not.
What does the field hold?
Who else reads the field's bytes?

Answer the questions above: the table then marks what fits your case and says why the rest does not.

Five USAGEs against the four things that decide between them (sizes and bytes from this lesson's runs)
USAGE Bytes for nine digits Exact decimal amounts Readable as text Same bytes on z/OS
DISPLAY Stores the value as: one character for each digit Poor one a digit: PIC S9(7)V99 took 9 bytes Good decimal digits, so 1234567.89 is kept exactly Good digit characters, with the sign hidden in the last byte Mixed same digits, other bytes: X'31' here, X'F1' in EBCDIC
COMP-3 Stores the value as: two digits a byte, then a sign Good 5 bytes: X'123456789C' Good decimal digits kept exactly Poor half-bytes that a text conversion would corrupt Good the same bytes: X'01234D' for -1234 in both
COMP or BINARY Stores the value as: a big-endian binary integer Good 4 bytes: X'075BCD15' Mixed exact, the decimals a scale of the PICTURE; IBM advises 8 digits or fewer Poor binary bytes are not characters Mixed big-endian in both, but 1 or 2 digits take 1 byte here and 2 on z/OS
COMP-5 Stores the value as: binary in the machine's byte order Good 4 bytes, as COMP Mixed exact, but values may pass the PICTURE up to the binary limit Poor binary bytes are not characters Poor machine order: X'D204' for 1234 here, big-endian on z/OS
COMP-2 Stores the value as: 8-byte floating point Mixed 8 bytes, whatever the digits Poor approximate: 0.10 has no exact binary floating-point value Poor floating-point bytes are not characters Poor IEEE here, hexadecimal floating point on z/OS
How the answers decide
  • “What does the field hold?” An amount of money: rules out COMP-2. Most decimal fractions have no exact floating-point value, so sums of amounts drift from what the ledger expects.
  • “What does the field hold?” An amount of money: adds a caveat to COMP or BINARY and COMP-5. The amount is exact, but its decimals are only a scale of the PICTURE; IBM advises PACKED-DECIMAL above eight digits.
  • “What does the field hold?” A count or a subscript: adds a caveat to DISPLAY and COMP-3. IBM advises USAGE BINARY for items used mainly in arithmetic or as subscripts: binary operations are faster than decimal ones.
  • “What does the field hold?” A count or a subscript: rules out COMP-2. A count is a whole number, and floating point brings approximation and 8 bytes for no gain.
  • “What does the field hold?” A measurement, where range matters more than decimals: adds a caveat to DISPLAY, COMP-3, COMP or BINARY and COMP-5. A decimal PICTURE has a fixed number of digits, so it must be sized for the largest and smallest value; COMP-2 covers a wide range in 8 bytes.
  • “Who else reads the field's bytes?” People, a report or a text file: rules out COMP-3, COMP or BINARY, COMP-5 and COMP-2. Only DISPLAY holds characters. Binary and packed bytes are not text, and a text conversion of a file changes them.
  • “Who else reads the field's bytes?” A COBOL program on z/OS: rules out COMP-5 and COMP-2. COMP-5 takes the byte order of the machine, and COMP-2 its floating-point format: neither has the same bytes on z/OS.
  • “Who else reads the field's bytes?” A COBOL program on z/OS: adds a caveat to COMP or BINARY and DISPLAY. Build COMP layouts with -std=ibm so that 1- and 2-digit items take 2 bytes; DISPLAY arrives in EBCDIC, with the sign in the last zone.
  • “Who else reads the field's bytes?” A C program on the same machine: rules out DISPLAY and COMP-3. A C program reads binary integers and floating point; digits kept as characters or as packed half-bytes need a conversion first.
  • “Who else reads the field's bytes?” A C program on the same machine: adds a caveat to COMP or BINARY. COMP is big-endian. A C program on this little-endian machine reads its two bytes in the other order; COMP-5 uses the order C uses.
  • “Who else reads the field's bytes?” Only this program: Nobody else reads the bytes, so decide by what the field holds: size and exactness.

In short: DISPLAY where people or text files read the digits, COMP-3 for amounts that are stored and calculated, COMP or BINARY for counters and subscripts, COMP-5 for numbers shared with C on the same machine, and COMP-2 for measurements, never for money.

Checkpoint

Check: Choosing a USAGE

  1. One question An amount of up to 9,999,999.99 goes into a record that a COBOL program on z/OS reads after a binary transfer. Which USAGE?

    Choose one answer.

    Show the answer: One question

    Answer: PIC S9(7)V99 COMP-3

    COMP-3 is exact and byte-identical in both compilers: -1234 was X'01234D' in GnuCOBOL and in IBM's table.

Practise: read the bytes before you run them

Size each item and read each set of bytes before you look at the answer. The questions take their values from this lesson’s runs, start with the idea you know least, and explain each wrong choice by the byte it misread:

Practice that adapts to you

Practise this lesson

15 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 15 How many bytes does PIC S9999 take in USAGE DISPLAY?

    Type a number.

    Show the answer: Question 1 of 15

    Answer: 4 bytes

    One byte a digit, and the S adds none: the session printed 4 and 31323374 for -1234.

  2. Question 2 of 15 How large are COMP-1 and COMP-2 items?

    Choose one answer.

    Show the answer: Question 2 of 15

    Answer: 4 and 8 bytes, whatever the value

    The session printed size 4 for COMP-1 and 8 for COMP-2 for the same value, -1234.

  3. Question 3 of 15 For -1234 in PIC S9999, which USAGEs gave the same bytes in GnuCOBOL as in IBM's table for z/OS?

    Choose every answer that is right.

    Show the answer: Question 3 of 15

    Answer:

    • COMP
    • COMP-3

    Packed decimal and binary COMP carry the same bytes across both compilers; DISPLAY and floating point do not.

  4. Question 4 of 15 In GnuCOBOL's default build, what is the last byte of -1234 in PIC S9999?

    Choose one answer.

    Show the answer: Question 4 of 15

    Answer: X'74', the character t

    The session printed 31323374 and 123t for -1234 and 31323334 for +1234.

  5. Question 5 of 15 A file translated from EBCDIC holds an amount 123M. What did the default GnuCOBOL build read it as, and what fixes it?

    Choose one answer.

    Show the answer: Question 5 of 15

    Answer: 1230; build with -fsign=EBCDIC, which read it as -1234

    The same four bytes were 1230 in one build and -1234 in the other: the sign convention is part of the data's description.

  6. Question 6 of 15 Which half-byte holds the sign of PIC S9999 DISPLAY on z/OS, and what is it for a negative value?

    Choose one answer.

    Show the answer: Question 6 of 15

    Answer: The zone of the last byte, D

    IBM accepts C, A, E and F as positive signs and D and B as negative ones, and writes C, D and F itself.

  7. Question 7 of 15 What value is X'04250D' in PIC S9(3)V99 COMP-3?

    Choose one answer.

    Show the answer: Question 7 of 15

    Answer: -42.50

    Read the digits off the hexadecimal, take the sign from the last half-byte, and place the point by the PICTURE.

  8. Question 8 of 15 Which sign half-byte does an unsigned packed item, PIC 9(5) COMP-3, hold?

    Choose one answer.

    Show the answer: Question 8 of 15

    Answer: F

    PIC 9(5) and PIC S9(5) are both 3 bytes; only the last half-byte differs, F or C.

  9. Question 9 of 15 A new packed field must hold amounts up to 9999. Which PICTURE do you choose, and why?

    Choose one answer.

    Show the answer: Question 9 of 15

    Answer: PIC S9(5) COMP-3, which takes the same 3 bytes as S9(4) with room to spare

    S9(4) and S9(5) both take 3 bytes, so the odd count adds a digit for free.

  10. Question 10 of 15 How many bytes does IBM Enterprise COBOL give a binary item of 5 to 9 digits?

    Choose one answer.

    Show the answer: Question 10 of 15

    Answer: 4

    PIC S9(9) COMP was 4 bytes in both of the lesson's builds; the dialects differ only for 1 or 2 digits.

  11. Question 11 of 15 A copybook built with GnuCOBOL's default dialect describes a record 1 byte shorter than z/OS writes it. Which field is the likely cause?

    Choose one answer.

    Show the answer: Question 11 of 15

    Answer: A PIC S9 or S99 COMP field, 1 byte here and 2 on z/OS

    BRANCH-COUNTS was 7 bytes by default and 8 with -std=ibm, because of BC-BRANCH, PIC S9(2) COMP.

  12. Question 12 of 15 DISPLAY of 25000000.00 in PIC S9(13)V99 COMP-5 printed +00000000002500000000. What do you change?

    Choose one answer.

    Show the answer: Question 12 of 15

    Answer: Move the item to an edited item and display that

    GnuCOBOL 3.2 printed a COMP-5 item with decimal places as its scaled integer; an edited item prints the amount.

  13. Question 13 of 15 Which USAGE does IBM advise for an item used mainly as a subscript?

    Choose one answer.

    Show the answer: Question 13 of 15

    Answer: BINARY, signed, with eight digits or fewer

    IBM's "Choosing efficient computational data items" names BINARY for subscripts and arithmetic, with an S and eight digits or fewer.

  14. Question 14 of 15 A COBOL program passes a 4-byte integer to a C function on the same Linux or macOS machine. Which USAGE?

    Choose one answer.

    Show the answer: Question 14 of 15

    Answer: COMP-5

    1234 was X'D204' in COMP-5 on this machine, the order a C int uses here, and X'04D2' in COMP.

  15. Question 15 of 15 A field of an export file is opened in a spreadsheet by people. Which USAGE do you give it?

    Choose one answer.

    Show the answer: Question 15 of 15

    Answer: DISPLAY, ideally with a separate sign or an edited picture

    Text readers need characters. The sign in the last zone is legal but surprising, so a file for people shows it separately.

Decode a record by hand

The bytes 000C 04D2 075BCD15 are BRANCH-COUNTS from the -std=ibm build. Split them by the table of binary sizes, convert each part with MySmartCoPilot’s number base converter, and check that you get 12, 1234 and 123456789.

Interview questions

Warm-up (fresher to 2–5 years): what is packed decimal, and how many bytes does PIC S9(7)V99 COMP-3 take?

Packed decimal, USAGE COMP-3 or PACKED-DECIMAL, stores two decimal digits in each byte, one in each half-byte, and adds one half-byte at the right for the sign: C for positive, D for negative and F for an unsigned item. The decimal point is not stored; the PICTURE says where it falls. PIC S9(7)V99 has nine digits, so with the sign it needs ten half-bytes, which is 5 bytes, against 9 in USAGE DISPLAY. The value 1234567.89 is stored as X’123456789C’. A useful rule is digits divided by 2, rounded down, plus 1. An even digit count wastes the leftmost half-byte, so PIC S9(4) and PIC S9(5) both take 3 bytes, which is why IBM recommends odd digit counts. Packed bytes are also the same in GnuCOBOL and on z/OS.

Two harder questions apply these ideas: amounts that turned to nonsense after a file transfer, and a copybook whose record came out one byte short. Work out your answer first, then open each first step:

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Mid to senior

    A daily extract from z/OS arrives on a Linux server through a transfer set to text mode. Names and dates read correctly, but every amount, a PIC S9(7)V99 COMP-3 field, is nonsense, and some records are a byte longer. What happened, and how should the extract be sent and read?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    A copybook of counters, PIC S9(2) COMP, PIC S9(4) COMP and PIC S9(9) COMP, builds cleanly with GnuCOBOL, but the record it describes is 7 bytes while the file written on z/OS has 8, and every field after the first one reads wrong. Why, and how do you fix and guard it?

    Model answer, Pro. First step and follow-ups

Organisations named on this page

MySmartCoPilot is independent of IBM and the GnuCOBOL project. The storage formats cited here come from their documentation, listed under References. The z/OS bytes are quoted from IBM’s table, and every other byte shown was printed by a GnuCOBOL 3.2 run.

Flashcards · 8 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. How many bytes does -1234 in PIC S9999 take as DISPLAY, COMP-3 and COMP?

    4 as DISPLAY, a byte a digit; 3 as packed decimal, two digits a byte plus a sign; 2 as binary COMP.

  2. Where does a signed zoned decimal item keep its sign?

    In the zone, the left half-byte, of its last byte. On z/OS -1234 is F1 F2 F3 D4, and a text copy shows that last byte as a letter, M: an overpunch.

  3. What do the sign half-bytes C, D and F mean in packed decimal?

    C positive, D negative and F unsigned, in the rightmost half-byte. -42.50 in PIC S9(3)V99 COMP-3 is X'04250D', and the PICTURE says where the point goes.

  4. How do you size a packed decimal item?

    Digits divided by 2, rounded down, plus 1: the nine digits of S9(7)V99 need 5 bytes packed, against 9 as DISPLAY.

  5. Why do IBM's guides advise an odd digit count for packed items?

    An even count leaves the leftmost half-byte without a digit: S9(4) COMP-3 takes 3 bytes, exactly as S9(5) does.

  6. How many bytes does PIC S9(2) COMP take?

    1 in GnuCOBOL's default dialect, whose binary-size is 1-2-4-8, and 2 under IBM's rules and -std=ibm, 2-4-8. A record shared with z/OS is built with -std=ibm.

  7. How does COMP-5 differ from COMP?

    COMP is big-endian in both compilers. COMP-5 is native binary in the byte order of the machine, so 1234 is X'D204' on a little-endian Mac, and it may hold values up to the capacity of its bytes.

  8. Which USAGE suits amounts, counters and numbers passed to C?

    Packed decimal, COMP-3, for amounts that are stored and calculated; binary COMP for counters and subscripts; COMP-5 for numbers shared with C on the same machine. Floating point never holds money.

Key takeaways

  • USAGE sets the bytes of a number: -1234 as PIC S9999 took 4 bytes in DISPLAY, 3 in COMP-3 and 2 in COMP and COMP-5, and as floating point 4 bytes in COMP-1 and 8 in COMP-2.
  • Zoned decimal keeps one digit a byte and the sign in the zone of the last byte, so -1234 read 123t in GnuCOBOL’s default build, 123M with -fsign=EBCDIC and F1F2F3D4 on z/OS.
  • Packed decimal keeps two digits a byte and a sign half-byte, C, D or F, so -42.50 in S9(3)V99 is X’04250D’, and an odd digit count wastes no half-byte.
  • Binary sizes follow the dialect, 1 byte for 1 or 2 digits in GnuCOBOL’s default and 2 under IBM’s rules and -std=ibm, and COMP-5 follows the machine’s byte order, X’D204’ for 1234 here.
  • Choose DISPLAY for text readers, COMP-3 for amounts, BINARY for counters and subscripts, COMP-5 for C on the same machine, and floating point only where approximation is acceptable.

Terms in this lesson

big-endian
A byte order that stores the most significant byte first, so 1234 in two bytes is X'04D2'. COBOL's BINARY and COMP items use it in GnuCOBOL and on z/OS; COMP-5 takes the order of the machine.
half-byte
Four bits, written as one hexadecimal digit. A byte is two half-bytes, so X'4D' has the half-bytes 4 and D; packed decimal keeps one digit or the sign in each.
overpunch
A sign kept in the zone of a number's last digit instead of a byte of its own. An EBCDIC record translated to ASCII shows it as a letter or a brace, so -1234 reads 123M.
packed decimal
USAGE PACKED-DECIMAL or COMP-3: two decimal digits in each byte and a sign in the last half-byte, C for positive, D for negative and F for unsigned, so PIC S9(5) takes 3 bytes.
USAGE clause
The clause that says how an item's value is stored: DISPLAY as characters, PACKED-DECIMAL or COMP-3 as packed digits, BINARY, COMP or COMP-5 as binary integers, and COMP-1 or COMP-2 as floating point.
zoned decimal
A number in USAGE DISPLAY: one digit a byte, kept as a character, with the sign of a signed item in the zone, the left half-byte, of its last byte unless SIGN ... SEPARATE gives the sign a byte of its own.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.