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.
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:
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. 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
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:
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. 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:
The drawing shows the whole scene; its 6 steps are listed below.
Every step as text
- 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.
- 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.
- 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.
- Silence. Nothing reports it. The program carries on with a total 10,000 too small, and every statement after it uses the wrong value.
- 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.
- 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
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
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:
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. 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:
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- 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.
- 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.
- 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.
- 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.
- 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
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:
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. 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
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.
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.
-
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?
-
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.
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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
- Enterprise COBOL for z/OS 6.5: ADD statement (IBM)
- Enterprise COBOL for z/OS 6.5: COMPUTE statement (IBM)
- Enterprise COBOL for z/OS 6.5: DIVIDE statement (IBM)
- Enterprise COBOL for z/OS 6.5: SIZE ERROR phrases (IBM)
- Enterprise COBOL for z/OS 6.5: TRUNC compiler option (IBM)
- Enterprise COBOL for z/OS 6.5: MOD function (IBM)
- Enterprise COBOL for z/OS 6.5: REM function (IBM)
- z/OS MVS System Codes: 0Cx (IBM)
- GnuCOBOL manual: compiler options (GnuCOBOL project (GNU))
- GnuCOBOL 3.2 dialect configuration: ibm-strict.conf (GnuCOBOL project (GNU))
- GnuCOBOL Programmer's Guide for GnuCOBOL 3.2 (GnuCOBOL project (GNU))
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress