MODULE 5 · LOOPS AND PROGRAM STRUCTURE · 4/7

PERFORM VARYING and nested loops

15 min30 XPExercise

PERFORM VARYING is COBOL's counting loop, the equivalent of for in other languages. It sets a counter, tests a condition, runs the body, and steps the counter:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. VARYDEMO.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-I           PIC 9(2).
       PROCEDURE DIVISION.
           PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 3
               DISPLAY "PASS " WS-I
           END-PERFORM
           DISPLAY "AFTER THE LOOP WS-I IS " WS-I
           PERFORM VARYING WS-I FROM 10 BY -5 UNTIL WS-I < 1
               DISPLAY "COUNTDOWN " WS-I
           END-PERFORM
           STOP RUN.

Output:

PASS 01
PASS 02
PASS 03
AFTER THE LOOP WS-I IS 04
COUNTDOWN 10
COUNTDOWN 05

The sequence is: set WS-I to the FROM value, test UNTIL, run the body, add the BY value, test again. The test comes first (like TEST BEFORE), so when the loop ends the counter has already gone one step past the last value used. Here that is 4, not 3.

FROM and BY can be literals or data items, and BY can be negative.

The PIC 9 trap

The counter must be able to hold the value that ends the loop:

       01  WS-I           PIC 9.
      *    ...
           PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 9

WS-I can never be greater than 9. When it is 9 and the loop adds 1, the result 10 is truncated to 0 and the loop starts again. It never ends. GnuCOBOL warns you ('WS-I' may not be GREATER THAN 9), but many compilers say nothing. Make counters one digit bigger than the limit.

Nested loops with AFTER

To walk every combination of two counters, add an AFTER clause. The AFTER counter changes fastest, like the minutes hand of a clock:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. GRID.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-ROW         PIC 9.
       01  WS-COL         PIC 9.
       PROCEDURE DIVISION.
           PERFORM 1000-SHOW-CELL
               VARYING WS-ROW FROM 1 BY 1 UNTIL WS-ROW > 2
                 AFTER WS-COL FROM 1 BY 1 UNTIL WS-COL > 3
           STOP RUN.

       1000-SHOW-CELL.
           DISPLAY "ROW " WS-ROW " COL " WS-COL.

Output:

ROW 1 COL 1
ROW 1 COL 2
ROW 1 COL 3
ROW 2 COL 1
ROW 2 COL 2
ROW 2 COL 3

For each value of WS-ROW, WS-COL restarts at 1 and runs to the end. COBOL allows several AFTER clauses, which you will use for tables with two or three dimensions in the next module.

AFTER is normally used with the out-of-line form, as above. For inline code, nest two PERFORM VARYING ... END-PERFORM blocks instead:

           PERFORM VARYING WS-ROW FROM 1 BY 1 UNTIL WS-ROW > 2
               PERFORM VARYING WS-COL FROM 1 BY 1 UNTIL WS-COL > 3
                   DISPLAY "ROW " WS-ROW " COL " WS-COL
               END-PERFORM
           END-PERFORM

On the job

Loop counters are usually PIC S9(4) COMP (binary) rather than display digits, because binary arithmetic is faster on the mainframe. You will see names like WS-SUB, WS-IX or I in older code.

Your task

The loans department wants a quick interest lookup table. Read two lines:

  1. The largest loan amount, e.g. 3000
  2. The highest annual rate in whole percent, from 1 to 9, e.g. 2

For every loan amount from 1000 up to the largest amount in steps of 1000, and for every rate from 1% up to the highest rate, display one line with a year's simple interest (amount * rate / 100):

AMOUNT  1000 RATE 01% INTEREST    10.00
AMOUNT  1000 RATE 02% INTEREST    20.00
AMOUNT  2000 RATE 01% INTEREST    20.00
...

Amount is the outer loop and rate the inner loop. If the largest amount is under 1000, display nothing.

The starter has the paragraph that calculates and displays one line. Use a single PERFORM ... VARYING ... AFTER to drive it.

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.