MODULE 3 · ARITHMETIC · 4/8

ON SIZE ERROR

14 min30 XPExercise

What happens when a result is too big for its field? Run this:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. OVERFLOW.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-X      PIC 99 VALUE 95.
       01  WS-Y      PIC 99 VALUE 95.
       PROCEDURE DIVISION.
           ADD 10 TO WS-X
           DISPLAY "WITHOUT CHECK: " WS-X
           ADD 10 TO WS-Y
               ON SIZE ERROR
                   DISPLAY "SIZE ERROR, WS-Y STILL " WS-Y
               NOT ON SIZE ERROR
                   DISPLAY "OK"
           END-ADD
           STOP RUN.

Output:

WITHOUT CHECK: 05
SIZE ERROR, WS-Y STILL 95

95 + 10 = 105, which needs three digits. Without a check, the leading 1 is silently lost and WS-X becomes 05 — a customer's balance of 105,000 turning into 5,000 is exactly this bug. With ON SIZE ERROR, the receiving field is left unchanged and your error code runs instead.

What counts as a size error

  • The integer part of the result doesn't fit the receiving field. (Extra decimal places are not a size error — they're truncated, or rounded if you said ROUNDED.)
  • Division by zero.
  • Rounding pushes the value over the top: 9.996 into PIC 9V99 with ROUNDED would need 10.00, so that's a size error too.

The full shape

Every arithmetic verb takes the same optional phrases:

           DIVIDE WS-TOTAL BY WS-COUNT GIVING WS-AVERAGE ROUNDED
               ON SIZE ERROR
                   MOVE ZERO TO WS-AVERAGE
                   DISPLAY "CANNOT AVERAGE"
               NOT ON SIZE ERROR
                   DISPLAY "AVERAGE CALCULATED"
           END-DIVIDE

NOT ON SIZE ERROR runs only when the arithmetic succeeded. Both branches can hold several statements. The scope terminator END-DIVIDE (or END-ADD, END-SUBTRACT, END-MULTIPLY, END-COMPUTE) marks where the error branch ends. Leave it out and the next statements — up to the next period — are swallowed into the NOT ON SIZE ERROR branch. The conditions module shows how nasty that gets; for now, always write the terminator.

Division by zero without a check

In GnuCOBOL, DIVIDE by zero with no ON SIZE ERROR leaves the target unchanged and carries on. On z/OS the same code can abend the job (typically a S0CB decimal-divide exception) at 3 a.m. Either test the divisor first or use ON SIZE ERROR — never rely on what happens by default.

On the job

Shop standards often require ON SIZE ERROR on every COMPUTE or DIVIDE that feeds a money field, with the error branch writing a message and setting a return code so operations can see the run needs attention.

Your task

A savings account balance is held in WS-BALANCE PIC 9(5)V99, so it can't exceed 99,999.99. The program reads the current balance, a deposit and a number of months, one per line.

  1. Add the deposit to WS-BALANCE. If it doesn't fit, display DEPOSIT REJECTED and leave the balance as it was; otherwise display DEPOSIT ACCEPTED.
  2. Display BALANCE: followed by the balance through WS-OUT.
  3. Divide the balance by the number of months, rounded to the cent, into WS-MONTHLY. If that fails (0 months), display MONTHLY: N/A; otherwise display MONTHLY: and the amount through WS-OUT.

For 90000.00, 5000.50, 12:

DEPOSIT ACCEPTED
BALANCE: 95,000.50
MONTHLY:  7,916.71
fixed format
Run your program to see its output here. The first visible test's input and datasets are used.
Submit to grade your program against every test.