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

Arithmetic statements, overflow and ON SIZE ERROR

Write COBOL ADD, SUBTRACT, MULTIPLY, DIVIDE and COMPUTE, see what overflow stores without ON SIZE ERROR, compare binary truncation and handle zero divisors.

  • 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

  • Write ADD, SUBTRACT, MULTIPLY, DIVIDE and COMPUTE with GIVING, REMAINDER and ROUNDED
  • Detect overflow with ON SIZE ERROR and explain what happens without it
  • Compare binary truncation under IBM's TRUNC options with GnuCOBOL's dialect settings
  • Handle division by zero explicitly

Before you start

What you’ll learn · Before you start

What you will learn

  • Write ADD, SUBTRACT, MULTIPLY, DIVIDE and COMPUTE with GIVING, REMAINDER and ROUNDED
  • Detect overflow with ON SIZE ERROR and explain what happens without it
  • Compare binary truncation under IBM's TRUNC options with GnuCOBOL's dialect settings
  • Handle division by zero explicitly

Before you start

On this page

Add 1500 to a balance of 9000 kept in PIC S9(4) and the balance becomes 500, with no message, no error and no change in how the program ends. COBOL drops the digits a receiver cannot hold unless the statement asks to be told, and whether a binary item overflows at all depends on the dialect and the compiler’s options.

Below you will write the five arithmetic statements with GIVING, REMAINDER and ROUNDED, catch an overflow with ON SIZE ERROR, compare how GnuCOBOL’s dialects and IBM’s TRUNC option treat binary results, read the signs of quotients and remainders, and handle a divisor of zero on purpose.

Each statement says which item gets the result

COBOL has five arithmetic statements, and the form of each says which item receives the result. ADD A TO B and SUBTRACT A FROM B change B. MULTIPLY A BY B stores the product in B, and DIVIDE A INTO B stores B divided by A in B. With GIVING, the operands are only read and the result goes to the item after GIVING. COMPUTE takes a whole arithmetic expression, written with +, -, *, / and **, and stores it in the item before the equals sign. This program runs each of them on one account:

statements.cob: five statements on one account COB · statements.cob
       IDENTIFICATION DIVISION.
       PROGRAM-ID. STATEMENTS.
      * The five arithmetic statements on one account: which item
      * each one changes, and the trap of MULTIPLY ... BY.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  BALANCE      PIC S9(7)V99 VALUE 12500.00.
       01  DEPOSIT      PIC S9(7)V99 VALUE 2500.00.
       01  FEE          PIC S9(5)V99 VALUE 25.00.
       01  QTY          PIC S9(3)    VALUE 3.
       01  PRICE        PIC S9(5)V99 VALUE 199.99.
       01  TOTAL        PIC S9(7)V99.
       01  SHARE-AMT    PIC S9(7)V99.
       01  LEFT-OVER    PIC S9(7)V99.
       01  RATE         PIC SV9(4)   VALUE .0725.
       01  INTEREST     PIC S9(5)V99.
       01  E-OUT        PIC -(7)9.99.
       PROCEDURE DIVISION.
           ADD DEPOSIT TO BALANCE
           MOVE BALANCE TO E-OUT
           DISPLAY "ADD DEPOSIT TO BALANCE       BALANCE   " E-OUT
           SUBTRACT FEE FROM BALANCE
           MOVE BALANCE TO E-OUT
           DISPLAY "SUBTRACT FEE FROM BALANCE    BALANCE   " E-OUT
           MULTIPLY QTY BY PRICE GIVING TOTAL
           MOVE TOTAL TO E-OUT
           DISPLAY "MULTIPLY QTY BY PRICE GIVING TOTAL     " E-OUT
           DIVIDE TOTAL BY 4 GIVING SHARE-AMT REMAINDER LEFT-OVER
           MOVE SHARE-AMT TO E-OUT
           DISPLAY "DIVIDE TOTAL BY 4 GIVING     SHARE-AMT " E-OUT
           MOVE LEFT-OVER TO E-OUT
           DISPLAY "               REMAINDER     LEFT-OVER " E-OUT
           COMPUTE INTEREST ROUNDED = BALANCE * RATE / 12
           MOVE INTEREST TO E-OUT
           DISPLAY "COMPUTE INTEREST ROUNDED     INTEREST  " E-OUT
           MULTIPLY RATE BY BALANCE
           MOVE BALANCE TO E-OUT
           DISPLAY "MULTIPLY RATE BY BALANCE     BALANCE   " E-OUT
           STOP RUN.
What each statement stored Python · statements_session.py
from session import files, run

# The five statements on one account.
files("statements.cob")
run("""
cobc -x statements.cob
./statements
""")

Output

$ cobc -x statements.cob
$ ./statements
ADD DEPOSIT TO BALANCE       BALANCE      15000.00
SUBTRACT FEE FROM BALANCE    BALANCE      14975.00
MULTIPLY QTY BY PRICE GIVING TOTAL          599.97
DIVIDE TOTAL BY 4 GIVING     SHARE-AMT      149.99
               REMAINDER     LEFT-OVER        0.01
COMPUTE INTEREST ROUNDED     INTEREST        90.47
MULTIPLY RATE BY BALANCE     BALANCE       1085.68

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

Statement Item it changed Result
ADD DEPOSIT TO BALANCE BALANCE 15000.00
SUBTRACT FEE FROM BALANCE BALANCE 14975.00
MULTIPLY QTY BY PRICE GIVING TOTAL TOTAL 599.97
DIVIDE TOTAL BY 4 GIVING SHARE-AMT REMAINDER LEFT-OVER SHARE-AMT, LEFT-OVER 149.99 and 0.01
COMPUTE INTEREST ROUNDED = BALANCE * RATE / 12 INTEREST 90.47
MULTIPLY RATE BY BALANCE BALANCE 1085.68

The DIVIDE line shows REMAINDER: 599.97 split four ways is 149.9925, SHARE-AMT keeps 149.99, and IBM defines the remainder as the dividend minus the quotient times the divisor, so 0.01 is left over. COMPUTE with ROUNDED turned 90.4739… into 90.47. The last line is the classic slip: MULTIPLY RATE BY BALANCE was meant to work out a year’s interest and instead replaced the balance with it.

MULTIPLY A BY B overwrites B

Wrong: MULTIPLY RATE BY BALANCE to calculate interest, which stored 1085.68 in BALANCE. Right: MULTIPLY RATE BY BALANCE GIVING INTEREST, or COMPUTE INTEREST ROUNDED = BALANCE * RATE, which leave the balance alone.

Checkpoint

Check: Where each statement puts its result

  1. One question After MULTIPLY RATE BY BALANCE, which item holds the product?

    Choose one answer.

    Show the answer: One question

    Answer: BALANCE

    MULTIPLY a BY b stores the product in b. Write MULTIPLY RATE BY BALANCE GIVING INTEREST to keep BALANCE.

A result that does not fit loses its high-order digits

A size error: The condition of an arithmetic statement whose final result has more integer digits than its receiver holds, or that divides by zero. ON SIZE ERROR then keeps the receiver's old value and runs its statement. happens when a result, after its decimal point is lined up with the receiver’s, has more integer digits than the receiver holds, or when a divisor is zero. IBM’s rules give two outcomes. Without an ON SIZE ERROR phrase, “truncation rules apply”: the high-order digits are dropped and the rest is stored. With the phrase, the receiver “is not altered” and the phrase’s statement runs. This program adds 1500 to 9000 in four PIC S9(4) items of different USAGE, first without the phrase and then with it; the session builds it twice:

size-error.cob: 9000 + 1500 into PIC S9(4) COB · size-error.cob
       IDENTIFICATION DIVISION.
       PROGRAM-ID. SIZE-ERROR.
      * 9000 + 1500 into PIC S9(4) under four USAGEs: first with no
      * ON SIZE ERROR phrase, then with one.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  T-DISPLAY   PIC S9(4)        VALUE 9000.
       01  T-PACKED    PIC S9(4) COMP-3 VALUE 9000.
       01  T-BINARY    PIC S9(4) COMP   VALUE 9000.
       01  T-NATIVE    PIC S9(4) COMP-5 VALUE 9000.
       01  E-OUT       PIC -(5)9.
       PROCEDURE DIVISION.
           DISPLAY "without ON SIZE ERROR"
           ADD 1500 TO T-DISPLAY
           ADD 1500 TO T-PACKED
           ADD 1500 TO T-BINARY
           ADD 1500 TO T-NATIVE
           PERFORM SHOW-ALL
           DISPLAY "with ON SIZE ERROR"
           MOVE 9000 TO T-DISPLAY T-PACKED T-BINARY T-NATIVE
           ADD 1500 TO T-DISPLAY
               ON SIZE ERROR DISPLAY "  DISPLAY size error"
           END-ADD
           ADD 1500 TO T-PACKED
               ON SIZE ERROR DISPLAY "  COMP-3  size error"
           END-ADD
           ADD 1500 TO T-BINARY
               ON SIZE ERROR DISPLAY "  COMP    size error"
               NOT ON SIZE ERROR DISPLAY "  COMP    no size error"
           END-ADD
           ADD 1500 TO T-NATIVE
               ON SIZE ERROR DISPLAY "  COMP-5  size error"
               NOT ON SIZE ERROR DISPLAY "  COMP-5  no size error"
           END-ADD
           PERFORM SHOW-ALL
           ADD 30000 TO T-NATIVE
               ON SIZE ERROR DISPLAY "  COMP-5 + 30000: size error"
           END-ADD
           MOVE T-NATIVE TO E-OUT
           DISPLAY "  COMP-5  " E-OUT
           STOP RUN.
       SHOW-ALL.
           MOVE T-DISPLAY TO E-OUT
           DISPLAY "  DISPLAY " E-OUT
           MOVE T-PACKED TO E-OUT
           DISPLAY "  COMP-3  " E-OUT
           MOVE T-BINARY TO E-OUT
           DISPLAY "  COMP    " E-OUT
           MOVE T-NATIVE TO E-OUT
           DISPLAY "  COMP-5  " E-OUT.
Two builds, with and without ON SIZE ERROR Python · size_error_session.py
from session import files, run

# 9000 + 1500 into PIC S9(4), built with GnuCOBOL's default dialect and then with -std=ibm.
files("size-error.cob")
run("""
cobc -x size-error.cob
./size-error
cobc -x -std=ibm -o size-error-ibm size-error.cob
./size-error-ibm
""")

Output

$ cobc -x size-error.cob
$ ./size-error
without ON SIZE ERROR
  DISPLAY    500
  COMP-3     500
  COMP       500
  COMP-5   10500
with ON SIZE ERROR
  DISPLAY size error
  COMP-3  size error
  COMP    size error
  COMP-5  no size error
  DISPLAY   9000
  COMP-3    9000
  COMP      9000
  COMP-5   10500
  COMP-5 + 30000: size error
  COMP-5   10500
$ cobc -x -std=ibm -o size-error-ibm size-error.cob
$ ./size-error-ibm
without ON SIZE ERROR
  DISPLAY    500
  COMP-3     500
  COMP     10500
  COMP-5   10500
with ON SIZE ERROR
  DISPLAY size error
  COMP-3  size error
  COMP    no size error
  COMP-5  no size error
  DISPLAY   9000
  COMP-3    9000
  COMP     10500
  COMP-5   10500
  COMP-5 + 30000: size error
  COMP-5   10500

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

Look at the first build. Without the phrase, the DISPLAY, COMP-3 and COMP totals all became 500, which is 10500 with its high-order 1 dropped. With the phrase, each printed size error and kept 9000. Step through the two paths:

Interactive · step by step 9000 + 1500 into PIC S9(4), two ways Step through one ADD whose result does not fit, first without ON SIZE ERROR, then with it.
9000 + 1500 into PIC S9(4), two ways, step 6 of 6. Showing ADD 1500 TO TOTAL, Result 10500, Without the phrase, With ON SIZE ERROR, The run goes on, The phrase runs. In focus: The phrase runs.no phrasephrase codedADD 1500 TO TOTALTOTAL is 9000, S9(4)Result 105005 digits, room for 4Without the phraseTOTAL becomes 0500With ON SIZE ERRORTOTAL stays 9000The run goes ona wrong total, no messageThe phrase runsreject or report it

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

Every step as text
  1. The statement. TOTAL, PIC S9(4), holds 9000. ADD 1500 TO TOTAL asks for 10500, a result with five integer digits for a receiver that has room for four.
  2. A size error. The size error test looks at the final result only, after any rounding. 10500 does not fit four digits, so a size error has occurred, whatever the program does next.
  3. No phrase. Without ON SIZE ERROR, IBM's rule is that truncation applies: the high-order digit is dropped, and TOTAL holds 0500. The run printed 500 for the DISPLAY, COMP-3 and COMP totals.
  4. Silence. Nothing reports it. The program carries on with a total 10,000 too small, and every statement after it uses the wrong value.
  5. With the phrase. With ON SIZE ERROR, the receiver is not changed. TOTAL keeps 9000, as the three totals did in the run's second half.
  6. The handler. Then the statement after ON SIZE ERROR runs, and NOT ON SIZE ERROR is skipped. That is the place to reject the transaction, count it and set a return code.

IBM adds two details. The test looks at final results only, never at intermediate results inside a COMPUTE, and ROUNDED is applied before the test, so a value that rounds up past the receiver’s limit is a size error too. The NOT ON SIZE ERROR phrase runs when the result fits, as it did for the COMP-5 item.

Key idea

An overflow without ON SIZE ERROR is silent and drops high-order digits, so code the phrase on every statement whose result can outgrow its receiver, and keep the receiver’s old value when it runs.

Checkpoint

Check: Overflow and ON SIZE ERROR

  1. Question 1 of 2 A PIC S9(5) COMP-3 total holds 95000. What does it hold after ADD 7000 TO TOTAL, with no ON SIZE ERROR?

    Type a number.

    A hint

    Work out the sum, then keep the digits that fit.

    Show the answer: Question 1 of 2

    Answer: 2000

    102000 has six integer digits for five places, so the high-order 1 is dropped and 02000 is kept, as 10500 became 0500 in the lesson's run.

  2. Question 2 of 2 What does the receiver hold after a size error when ON SIZE ERROR is coded?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Its value from before the statement

    With ON SIZE ERROR the receiver keeps its value and the phrase runs; without it the result is truncated.

Binary receivers follow the dialect, not only the PICTURE

The COMP-5 total behaved differently in both builds: it became 10500, more than four digits, and raised no size error until 30000 more pushed it past 32,767, the limit of two signed bytes. The previous lesson showed why: COMP-5 is held to the capacity of its bytes, not to its PICTURE. The second build shows the trap. Under -std=ibm, GnuCOBOL stored 10500 in the PIC S9(4) COMP item as well, and its ON SIZE ERROR phrase did not run, because that dialect’s configuration sets binary-truncate to no; -fno-trunc does the same in the default dialect.

On z/OS the same choice is the TRUNC compiler option. TRUNC(STD), the default, truncates binary receivers to the number of digits in the PICTURE. TRUNC(BIN) truncates them only at the 2, 4 or 8-byte boundary and makes every binary item behave like COMP-5, which IBM handles that way whatever the option. TRUNC(OPT) lets the compiler truncate whichever way runs faster, and IBM warns that unpredictable results can occur when data does not fit the PICTURE. For ON SIZE ERROR, IBM’s Language Reference sets the limit of a BINARY, COMP, COMP-4 or COMP-5 receiver at its PICTURE, regardless of TRUNC.

PIC S9(4) receiver of 9000 + 1500 Stored without the phrase ON SIZE ERROR runs Source
DISPLAY or COMP-3, any build 0500 yes run
COMP, GnuCOBOL default dialect 0500 yes run
COMP, GnuCOBOL -std=ibm 10500 no run
COMP-5, GnuCOBOL either dialect 10500 no run
COMP, IBM TRUNC(STD) 0500 yes IBM’s documentation
COMP, IBM TRUNC(BIN) 10500 yes, the limit is the PICTURE IBM’s documentation
COMP-5, IBM, any TRUNC 10500 yes, the limit is the PICTURE IBM’s documentation

The last rows are what IBM documents rather than a run here. They differ from GnuCOBOL’s -std=ibm build, so overflow handling that passes on a laptop proves little about z/OS: test it with the compiler and options of production.

Trusting a binary total that passed its PICTURE

Wrong: relying on a COMP total that happens to keep 10500 in PIC S9(4) under -std=ibm or TRUNC(BIN). The same source stores 0500 under TRUNC(STD). Right: give binary items a PICTURE with room for the largest total, code ON SIZE ERROR, and build local tests with the truncation rule of production.

Checkpoint

Check: Binary truncation, TRUNC and dialects

  1. Question 1 of 2 Built with -std=ibm, what did GnuCOBOL store in the PIC S9(4) COMP total after 9000 + 1500, ON SIZE ERROR coded?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: 10500, with no size error

    IBM's Language Reference says the size error limit of a binary receiver is its PICTURE whatever TRUNC is, so test overflow handling on the compiler that runs in production.

  2. Question 2 of 2 What is the largest value GnuCOBOL kept in PIC S9(4) COMP-5 without a size error?

    Type a number.

    A hint

    Two bytes, signed.

    Show the answer: Question 2 of 2

    Answer: 32767

    COMP-5 is limited by its two bytes, -32,768 to 32,767, so 10500 fitted and 40500 raised a size error in the run.

DIVIDE truncates toward zero, and MOD and REM differ

DIVIDE without ROUNDED truncates its quotient toward zero, and its remainder is the dividend minus the quotient times the divisor, so the remainder takes the sign of the dividend. The intrinsic functions offer two other rules. IBM defines MOD with FUNCTION INTEGER, which rounds down to the greatest integer not above the quotient, and REM with FUNCTION INTEGER-PART, which cuts off the fraction. This program divides with negative operands:

divide.cob: signs of quotients and remainders COB · divide.cob
       IDENTIFICATION DIVISION.
       PROGRAM-ID. DIVIDE-SIGNS.
      * Quotients and remainders of negative operands: DIVIDE with
      * REMAINDER, the MOD and REM functions, INTEGER and INTEGER-PART.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  Q           PIC S9(3).
       01  R           PIC S9(3).
       01  N           PIC S9(3).
       01  LABEL-TEXT  PIC X(18).
       01  E-Q         PIC -(3)9.
       01  E-R         PIC -(3)9.
       01  E-N         PIC -(3)9.
       PROCEDURE DIVISION.
           DIVIDE 17 BY 5 GIVING Q REMAINDER R
           MOVE "17 BY 5" TO LABEL-TEXT
           PERFORM SHOW-QR
           DIVIDE -17 BY 5 GIVING Q REMAINDER R
           MOVE "-17 BY 5" TO LABEL-TEXT
           PERFORM SHOW-QR
           DIVIDE 17 BY -5 GIVING Q REMAINDER R
           MOVE "17 BY -5" TO LABEL-TEXT
           PERFORM SHOW-QR
           DIVIDE -18 BY 5 GIVING Q ROUNDED REMAINDER R
           MOVE "-18 BY 5, ROUNDED" TO LABEL-TEXT
           PERFORM SHOW-QR
           COMPUTE N = FUNCTION MOD(-17, 5)
           MOVE "MOD(-17, 5)" TO LABEL-TEXT
           PERFORM SHOW-N
           COMPUTE N = FUNCTION REM(-17, 5)
           MOVE "REM(-17, 5)" TO LABEL-TEXT
           PERFORM SHOW-N
           COMPUTE N = FUNCTION INTEGER(-2.5)
           MOVE "INTEGER(-2.5)" TO LABEL-TEXT
           PERFORM SHOW-N
           COMPUTE N = FUNCTION INTEGER-PART(-2.5)
           MOVE "INTEGER-PART(-2.5)" TO LABEL-TEXT
           PERFORM SHOW-N
           STOP RUN.
       SHOW-QR.
           MOVE Q TO E-Q
           MOVE R TO E-R
           DISPLAY LABEL-TEXT " quotient " E-Q "  remainder " E-R.
       SHOW-N.
           MOVE N TO E-N
           DISPLAY LABEL-TEXT " " E-N.
DIVIDE, MOD, REM, INTEGER and INTEGER-PART Python · divide_session.py
from session import files, run

# Quotients, remainders, MOD, REM, INTEGER and INTEGER-PART of negative operands.
files("divide.cob")
run("""
cobc -x divide.cob
./divide
""")

Output

$ cobc -x divide.cob
$ ./divide
17 BY 5            quotient    3  remainder    2
-17 BY 5           quotient   -3  remainder   -2
17 BY -5           quotient   -3  remainder    2
-18 BY 5, ROUNDED  quotient   -4  remainder   -3
MOD(-17, 5)           3
REM(-17, 5)          -2
INTEGER(-2.5)        -3
INTEGER-PART(-2.5)   -2

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

-17 BY 5 gave a quotient of -3 and a remainder of -2, and 17 BY -5 a quotient of -3 and a remainder of 2. MOD(-17, 5) was 3, because INTEGER(-3.4) is -4, while REM(-17, 5) was -2, the DIVIDE remainder. INTEGER(-2.5) was -3 and INTEGER-PART(-2.5) was -2. MOD takes the sign of the divisor instead, as IBM’s examples show with MOD(11, -5) = -4, so for a day of the week or a position in a cycle, with a positive divisor, MOD gives the answer that never goes negative.

The fourth line is a surprise: -18 BY 5 with a ROUNDED quotient stored -4, and still a remainder of -3. Step through why:

Interactive · stage by stage DIVIDE -18 BY 5 GIVING Q ROUNDED REMAINDER R Step down the column to see why Q and R do not fit back together.
DIVIDE -18 BY 5 GIVING Q ROUNDED REMAINDER R, step 5 of 5. Showing The quotient: -3.6, Q ROUNDED is -4, R uses -3, R = -18 - (-3 x 5), Q x 5 + R is -23. In focus: Q x 5 + R is -23.The quotient: -3.6-18 divided by 5Q ROUNDED is -4half or more: away from 0R uses -3a truncated copy of QR = -18 - (-3 x 5)R is -3, the sign of -18Q x 5 + R is -23not -18: use Q or R alone

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

Every step as text
  1. The exact quotient. The division -18 by 5 has the exact quotient -3.6. Q, PIC S9(3), has no decimal places, so the statement must drop the .6 one way or another.
  2. ROUNDED. ROUNDED looks at the first digit dropped, 6, which is 5 or more, so the last digit kept grows by one in size. -3.6 becomes -4, away from zero, as the run printed.
  3. The remainder's quotient. IBM's rule for DIVIDE with REMAINDER keeps the quotient in an intermediate field that is truncated rather than rounded, so the remainder is worked out from -3, not from the -4 stored in Q.
  4. The remainder. The remainder is the dividend minus the quotient times the divisor, -18 - (-3 x 5), which is -3. Truncating toward zero gives a remainder with the sign of the dividend.
  5. They do not add up. Q x 5 + R is -20 - 3, which is -23, not -18. With ROUNDED, Q and R describe two different quotients: use the remainder only with a truncated quotient.

Key idea

DIVIDE and REM truncate toward zero and keep the sign of the dividend, MOD rounds down and keeps the sign of the divisor, and a ROUNDED quotient need not match its REMAINDER.

Checkpoint

Check: Quotients, remainders, MOD and REM

  1. One question What are FUNCTION MOD(-17, 5) and FUNCTION REM(-17, 5)?

    Choose one answer.

    Show the answer: One question

    Answer: 3 and -2

    IBM defines MOD with INTEGER, which rounds down, and REM with INTEGER-PART, which truncates: the run printed 3 and -2.

A zero divisor needs a test or ON SIZE ERROR

An average of zero items divides by zero. This program tries it without the phrase, with DIVIDE and with COMPUTE, then with ON SIZE ERROR, and last with the divisor tested before the division:

zero-divide.cob: an average of zero items COB · zero-divide.cob
       IDENTIFICATION DIVISION.
       PROGRAM-ID. ZERO-DIVIDE.
      * An average over zero items: DIVIDE and COMPUTE without ON SIZE
      * ERROR, the exception the run records, then the same DIVIDE
      * with the phrase, and with the divisor tested first.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  TOTAL       PIC S9(5)V99 VALUE 1000.00.
       01  ITEM-COUNT  PIC S9(3)    VALUE 0.
       01  AVERAGE     PIC S9(5)V99 VALUE 77.00.
       01  E-OUT       PIC -(5)9.99.
       PROCEDURE DIVISION.
           DIVIDE TOTAL BY ITEM-COUNT GIVING AVERAGE
           MOVE AVERAGE TO E-OUT
           DISPLAY "DIVIDE, no phrase:    AVERAGE " E-OUT
           DISPLAY "exception status:     "
               FUNCTION EXCEPTION-STATUS
           COMPUTE AVERAGE = TOTAL / ITEM-COUNT
           MOVE AVERAGE TO E-OUT
           DISPLAY "COMPUTE, no phrase:   AVERAGE " E-OUT
           DIVIDE TOTAL BY ITEM-COUNT GIVING AVERAGE
               ON SIZE ERROR
                   MOVE ZERO TO AVERAGE
                   DISPLAY "ON SIZE ERROR ran:    AVERAGE set to 0"
           END-DIVIDE
           IF ITEM-COUNT = ZERO
               DISPLAY "divisor tested first: no items, no average"
           ELSE
               DIVIDE TOTAL BY ITEM-COUNT GIVING AVERAGE
           END-IF
           DISPLAY "the run carried on"
           STOP RUN.
Four ways to meet a zero divisor Python · zero_divide_session.py
from session import files, run

# A zero divisor with and without ON SIZE ERROR. A command that fails would be followed by "[exit status N]".
files("zero-divide.cob")
run("""
cobc -x zero-divide.cob
./zero-divide
""")

Output

$ cobc -x zero-divide.cob
$ ./zero-divide
DIVIDE, no phrase:    AVERAGE     77.00
exception status:     EC-SIZE-ZERO-DIVIDE
COMPUTE, no phrase:   AVERAGE     77.00
ON SIZE ERROR ran:    AVERAGE set to 0
divisor tested first: no items, no average
the run carried on

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

GnuCOBOL 3.2 left AVERAGE at its old value, 77.00, after both statements without the phrase, recorded the exception EC-SIZE-ZERO-DIVIDE, which FUNCTION EXCEPTION-STATUS returned, and carried on to its last line. GnuCOBOL’s own Programmer’s Guide says such a division ends the program with an error message, so the documentation and this build disagree. On z/OS a zero divisor in decimal arithmetic is a decimal-divide exception, system completion code 0CB, and in binary arithmetic a fixed-point-divide exception, 0C9.

One statement with three possible outcomes, a stale value, a stop or an abend, is reason enough to decide on purpose. A zero divisor that the business expects, such as an account with no transactions, gets its own branch, as the last block did. ON SIZE ERROR stays on the DIVIDE as a safety net for the cases nobody expected.

Name the case before you divide

Test the divisor with IF ITEM-COUNT = ZERO and write what the report should say, “no items”, instead of leaving the answer to whichever compiler and options run the program.

Checkpoint

Check: Division by zero

  1. One question In the lesson's run, what did AVERAGE hold after DIVIDE TOTAL BY ITEM-COUNT GIVING AVERAGE with ITEM-COUNT zero and no ON SIZE ERROR?

    Choose one answer.

    Show the answer: One question

    Answer: Its old value, 77.00, and the run went on

    A silent unchanged average is easy to miss, which is why the lesson tests the divisor or codes ON SIZE ERROR.

Practise: predict the result before the run

Each question takes its numbers from this lesson’s runs. Work out what the receiver holds before you choose; the explanations name the rule a wrong choice missed:

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 Which item does ADD A B GIVING C change?

    Choose one answer.

    Show the answer: Question 1 of 15

    Answer: Only C

    GIVING names the receiver. Without it, ADD and SUBTRACT store into the item after TO or FROM.

  2. Question 2 of 15 What does DIVIDE 4 INTO TOTAL do when TOTAL holds 599.97 in PIC S9(7)V99?

    Choose one answer.

    Show the answer: Question 2 of 15

    Answer: It stores 149.99 in TOTAL

    DIVIDE a INTO b is b / a, stored in b; DIVIDE b BY a GIVING c leaves b alone, as statements.cob did.

  3. Question 3 of 15 DIVIDE 599.97 BY 4 GIVING SHARE-AMT REMAINDER LEFT-OVER, with both receivers PIC S9(7)V99. How much is LEFT-OVER?

    Type a number.

    A hint

    The remainder is the dividend minus the stored quotient times the divisor.

    Show the answer: Question 3 of 15

    Answer: 0.01

    SHARE-AMT keeps 149.99, and 599.97 - 149.99 x 4 is 0.01: the paisa or cent that a split of the total cannot give to anyone, which the run printed.

  4. Question 4 of 15 Which digits does COBOL drop when a result is too large for its receiver and no ON SIZE ERROR is coded?

    Choose one answer.

    Show the answer: Question 4 of 15

    Answer: The high-order digits, on the left

    Truncation keeps the digits that fit at the right and drops the rest, without a message.

  5. Question 5 of 15 When does the statement after NOT ON SIZE ERROR run?

    Choose one answer.

    Show the answer: Question 5 of 15

    Answer: When the statement's result fitted its receiver

    The run printed "COMP-5 no size error" from its NOT ON SIZE ERROR phrase when 10500 fitted the COMP-5 item.

  6. Question 6 of 15 A posting program adds deposits to a PIC S9(7)V99 balance. What should happen when a deposit would make it overflow?

    Choose one answer.

    Show the answer: Question 6 of 15

    Answer: Code ON SIZE ERROR, keep the balance, write the transaction to a reject report and set a return code

    A size error is a business event: keep the data right, record what was refused, and tell the caller.

  7. Question 7 of 15 What is the default of IBM's TRUNC compiler option?

    Choose one answer.

    Show the answer: Question 7 of 15

    Answer: TRUNC(STD)

    Know the options a shop compiles with before trusting what binary arithmetic stores.

  8. Question 8 of 15 Under TRUNC(BIN), how does IBM truncate a PIC S9(4) COMP receiver?

    Choose one answer.

    Show the answer: Question 8 of 15

    Answer: Only at its two-byte boundary, as if it were COMP-5

    TRUNC(BIN) makes BINARY items behave like COMP-5, which IBM handles as TRUNC(BIN) whatever the option.

  9. Question 9 of 15 Your local tests build with -std=ibm and pass, but production z/OS uses TRUNC(STD). Which overflow behaviour differs?

    Choose one answer.

    Show the answer: Question 9 of 15

    Answer: A binary total past its PICTURE stays whole locally but is cut to the PICTURE on z/OS

    Match the binary truncation rule of production in your tests, or avoid relying on binary overflow at all.

  10. Question 10 of 15 What quotient and remainder does DIVIDE -17 BY 5 GIVING Q REMAINDER R give?

    Choose one answer.

    Show the answer: Question 10 of 15

    Answer: Q = -3, R = -2

    The run printed quotient -3 and remainder -2 for -17 BY 5.

  11. Question 11 of 15 What are FUNCTION INTEGER(-2.5) and FUNCTION INTEGER-PART(-2.5)?

    Choose one answer.

    Show the answer: Question 11 of 15

    Answer: -3 and -2

    The two only differ for negative values with a fraction, which is where MOD and REM differ too.

  12. Question 12 of 15 DIVIDE -18 BY 5 GIVING Q ROUNDED REMAINDER R printed Q = -4 and R = -3. Why does Q x 5 + R not give -18?

    Choose one answer.

    Show the answer: Question 12 of 15

    Answer: The remainder is worked out from a truncated quotient, -3, not from the rounded Q

    With ROUNDED, Q and R belong to different quotients; use the remainder with a truncated quotient.

  13. Question 13 of 15 Which exception did FUNCTION EXCEPTION-STATUS report after the division by zero?

    Choose one answer.

    Show the answer: Question 13 of 15

    Answer: EC-SIZE-ZERO-DIVIDE

    A division by zero is a size error condition; GnuCOBOL recorded it as EC-SIZE-ZERO-DIVIDE.

  14. Question 14 of 15 Which z/OS system completion code is a decimal-divide exception?

    Choose one answer.

    Show the answer: Question 14 of 15

    Answer: 0CB

    0CB for decimal data and 0C9 for binary data are the divide exceptions that an unchecked zero divisor risks on z/OS.

  15. Question 15 of 15 An average of zero items must print as "no items" in a report. Which code fits best?

    Choose one answer.

    Show the answer: Question 15 of 15

    Answer: IF ITEM-COUNT = ZERO, print "no items"; ELSE DIVIDE with ON SIZE ERROR as a safety net

    Zero items is an expected case, so it gets its own branch; ON SIZE ERROR guards the cases nobody expected.

Post a transaction safely

Write POST-TXN: a PIC S9(7)V99 COMP-3 balance, a deposit or withdrawal amount, ADD or SUBTRACT with ON SIZE ERROR, and MOVE 8 TO RETURN-CODE when a posting is refused. Try 9999990.00 plus 25.00, which must be refused with the balance unchanged, and 100.00 minus 25.50, which must give 74.50, then check the exit status with echo $?.

Interview questions

Warm-up (fresher to 2–5 years): what does ON SIZE ERROR do, and what happens without it?

ON SIZE ERROR is a phrase of ADD, SUBTRACT, MULTIPLY, DIVIDE and COMPUTE. A size error occurs when the final result has more integer digits than the receiver holds, after any rounding, or when a divisor is zero. With the phrase, the receiver keeps its old value and the statement after ON SIZE ERROR runs, so the program can reject or report the record; NOT ON SIZE ERROR runs when the result fits. Without the phrase the result is truncated on the left and stored with no message: 9000 + 1500 into PIC S9(4) left 0500. Binary items add a twist, because GnuCOBOL’s dialects and IBM’s TRUNC option decide whether a COMP receiver is cut to its PICTURE, so overflow handling is tested with the compiler options of production.

Two harder questions apply these ideas: a balance that wrapped without a message, and a binary total that differs between a laptop and z/OS. 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. Fresher to mid

    After a large deposit, a customer's balance in a PIC S9(7)V99 field shows 12,345.67 instead of 10,012,345.67, and the posting job ended with return code 0. How do you find the cause, and what do you change so it cannot happen silently again?

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

  2. Mid to senior

    A daily count kept in PIC S9(4) COMP passes your local tests, built with GnuCOBOL -std=ibm, even past 9,999, but on z/OS the same count wraps to small numbers and ON SIZE ERROR fires. Explain the difference and how you would make the local tests trustworthy.

    Model answer, Pro. First step and follow-ups

Organisations named on this page

MySmartCoPilot is independent of IBM and the GnuCOBOL project. The rules for arithmetic statements, size errors and TRUNC are cited from their documentation, listed under References. Every value a program printed here comes from a GnuCOBOL 3.2 run; the table’s rows marked IBM’s documentation are cited, not run.

Flashcards · 8 cards

Recall it, then check

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

  1. Which item does MULTIPLY RATE BY BALANCE change?

    BALANCE: the product replaces it. MULTIPLY RATE BY BALANCE GIVING INTEREST, or a COMPUTE, leaves the balance alone.

  2. What does 9000 + 1500 leave in PIC S9(4) when no ON SIZE ERROR is coded?

    0500. The high-order digit of 10500 is dropped and the rest is stored, with no message.

  3. What happens to the receiver when ON SIZE ERROR runs?

    It keeps its old value, and the statement of the phrase runs. NOT ON SIZE ERROR runs instead when the result fits.

  4. Is ROUNDED applied before or after the size-error test?

    Before: a value that rounds up past the receiver's limit is a size error too. The test reads final results only, never the intermediate results of a COMPUTE.

  5. Why could a PIC S9(4) COMP item hold 10500 under GnuCOBOL's -std=ibm?

    That dialect switches binary truncation off, so the limit is the item's bytes rather than its PICTURE, and ON SIZE ERROR did not run. COMP-5 behaves that way in every dialect.

  6. What do IBM's TRUNC(STD) and TRUNC(BIN) do to binary receivers?

    TRUNC(STD), the default, cuts them to the digits of the PICTURE; TRUNC(BIN) cuts only at the 2, 4 or 8-byte boundary. Test overflow handling with the options production uses.

  7. What are FUNCTION MOD(-17, 5) and FUNCTION REM(-17, 5)?

    MOD gives 3: it rounds the quotient down and keeps the divisor's sign. REM gives -2: like the remainder of DIVIDE, it truncates toward zero and keeps the dividend's sign.

  8. How should a program handle a divisor that may be zero?

    Test it first, IF ITEM-COUNT = ZERO, and write what that case should report, with ON SIZE ERROR as a safety net. GnuCOBOL 3.2 kept the old value; on z/OS it is an 0CB or 0C9 abend.

Key takeaways

  • Each arithmetic statement names its receiver: TO, FROM, BY and INTO change their second item, GIVING sends the result elsewhere, and MULTIPLY RATE BY BALANCE replaced the balance.
  • Without ON SIZE ERROR an overflow drops the high-order digits silently, so 9000 + 1500 left 0500; with the phrase the receiver kept 9000 and the phrase ran.
  • Binary receivers follow the dialect and the options: GnuCOBOL’s -std=ibm and COMP-5 kept 10500 in PIC S9(4) with no size error, while IBM documents a size error at the PICTURE whatever TRUNC is.
  • DIVIDE and REM truncate toward zero and keep the dividend’s sign, MOD rounds down, and a ROUNDED quotient does not match its remainder.
  • A zero divisor left GnuCOBOL’s receiver unchanged and is an 0CB or 0C9 abend on z/OS, so test the divisor and keep ON SIZE ERROR as a safety net.

Terms in this lesson

size error
The condition of an arithmetic statement whose final result has more integer digits than its receiver holds, or that divides by zero. ON SIZE ERROR then keeps the receiver's old value and runs its statement.

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.