Chapter 8 Exercises: Iteration -- The PERFORM Statement

Tier 1: Recall and Recognition (Exercises 1-8)

These exercises test your understanding of PERFORM syntax and basic concepts.


Exercise 1: Identify the PERFORM Form

For each of the following code fragments, identify which form of PERFORM is being used (Basic, THRU, TIMES, UNTIL with TEST BEFORE, UNTIL with TEST AFTER, VARYING, or Inline):

      * Fragment A:
           PERFORM CALCULATE-TAX

      * Fragment B:
           PERFORM 10 TIMES
               ADD 1 TO WS-COUNTER
           END-PERFORM

      * Fragment C:
           PERFORM WITH TEST AFTER
               UNTIL WS-RESPONSE = 'Q'
               PERFORM DISPLAY-MENU
               ACCEPT WS-RESPONSE
           END-PERFORM

      * Fragment D:
           PERFORM VALIDATE-START THRU VALIDATE-EXIT

      * Fragment E:
           PERFORM VARYING WS-I FROM 1 BY 1
               UNTIL WS-I > 50
               DISPLAY WS-TABLE-ENTRY(WS-I)
           END-PERFORM

      * Fragment F:
           PERFORM UNTIL WS-BALANCE < 0
               SUBTRACT WS-PAYMENT FROM WS-BALANCE
           END-PERFORM

      * Fragment G:
           PERFORM PRINT-HEADER 1 TIMES

Exercise 2: Predict the Output

What does the following code display? Trace the execution carefully.

       01  WS-X  PIC 9(2) VALUE 1.

       PROCEDURE DIVISION.
       MAIN-PARA.
           DISPLAY "Start"
           PERFORM PARA-A
           DISPLAY "Middle"
           PERFORM PARA-B
           DISPLAY "End"
           STOP RUN.

       PARA-A.
           DISPLAY "A-begin"
           PERFORM PARA-C
           DISPLAY "A-end".

       PARA-B.
           DISPLAY "B-begin"
           DISPLAY "B-end".

       PARA-C.
           DISPLAY "C-begin"
           DISPLAY "C-end".

Exercise 3: Sum of First N Numbers

Write a COBOL program that uses PERFORM VARYING to compute the sum of the first 100 natural numbers (1 + 2 + 3 + ... + 100). Display the result. Verify that the answer is 5050 (using the formula n(n+1)/2 = 100101/2 = 5050).


Exercise 4: PERFORM TIMES vs. PERFORM VARYING

Explain the difference between these two loops. Do they produce the same output? Why or why not?

      * Loop A:
           MOVE 0 TO WS-COUNTER
           PERFORM 5 TIMES
               ADD 1 TO WS-COUNTER
               DISPLAY WS-COUNTER
           END-PERFORM

      * Loop B:
           PERFORM VARYING WS-COUNTER FROM 1 BY 1
               UNTIL WS-COUNTER > 5
               DISPLAY WS-COUNTER
           END-PERFORM

Exercise 5: Multiplication Table

Write a COBOL program that prints a 10x10 multiplication table. Use nested PERFORM VARYING loops (either with AFTER or nested inline). The output should be a neatly formatted grid showing products from 1x1 to 10x10.


Exercise 6: TEST BEFORE vs. TEST AFTER

For each scenario below, state whether you would use WITH TEST BEFORE or WITH TEST AFTER, and explain why:

a) Reading records from a file until end-of-file b) Displaying a menu and processing user choices until they select "Quit" c) Computing Fibonacci numbers until one exceeds 1,000,000 d) Prompting for a password with a maximum of 3 attempts e) Processing all elements of an array


Exercise 7: Condition Names in Loops

Rewrite the following loop to use 88-level condition names instead of the relational condition:

       01  WS-STATUS  PIC X(1) VALUE SPACES.

           MOVE 'N' TO WS-STATUS
           PERFORM UNTIL WS-STATUS = 'Y'
               PERFORM PROCESS-RECORD
               PERFORM CHECK-FOR-COMPLETION
           END-PERFORM

Exercise 8: Find the Bugs

Each of the following code fragments contains a bug related to PERFORM. Identify and explain each bug:

      * Bug A: Infinite loop
           PERFORM UNTIL WS-COUNTER > 10
               DISPLAY WS-COUNTER
           END-PERFORM

      * Bug B: Unexpected behavior
           MOVE 5 TO WS-LIMIT
           PERFORM WS-LIMIT TIMES
               SUBTRACT 1 FROM WS-LIMIT
               DISPLAY "Iteration"
           END-PERFORM

      * Bug C: Missing priming read
           SET NOT-END-OF-FILE TO TRUE
           PERFORM UNTIL END-OF-FILE
               PERFORM PROCESS-RECORD
               PERFORM READ-RECORD
           END-PERFORM

      * Bug D: Off-by-one
           PERFORM VARYING WS-I FROM 1 BY 1
               UNTIL WS-I = 10
               DISPLAY WS-TABLE(WS-I)
           END-PERFORM

Tier 2: Understanding and Application (Exercises 9-16)

These exercises require you to write working code and demonstrate understanding of PERFORM patterns.


Exercise 9: Factorial Calculator

Write a COBOL program that calculates and displays the factorials of 1 through 15. Use PERFORM VARYING with an accumulator. Display each factorial on a separate line (e.g., "5! = 120").


Exercise 10: Temperature Conversion Table

Write a COBOL program that produces a Fahrenheit-to-Celsius conversion table for temperatures from -40 to 212 degrees Fahrenheit in steps of 10. Use PERFORM VARYING with a step value of 10. Format the output in two neat columns with headers.

The formula is: C = (F - 32) * 5 / 9


Exercise 11: Array Reversal

Write a COBOL program that: 1. Initializes a 10-element numeric array with the values 10, 20, 30, ..., 100. 2. Displays the array. 3. Reverses the array in-place using a PERFORM UNTIL loop with two converging index variables (left and right). 4. Displays the reversed array.


Exercise 12: Convert PERFORM TIMES to PERFORM VARYING

Rewrite the following code using PERFORM VARYING instead of PERFORM TIMES:

           MOVE ZEROS TO WS-SUM
           MOVE ZEROS TO WS-COUNTER
           PERFORM 20 TIMES
               ADD 1 TO WS-COUNTER
               COMPUTE WS-SQUARE = WS-COUNTER * WS-COUNTER
               ADD WS-SQUARE TO WS-SUM
               DISPLAY WS-COUNTER " squared = " WS-SQUARE
           END-PERFORM
           DISPLAY "Sum of squares: " WS-SUM

Exercise 13: Convert PERFORM VARYING to PERFORM UNTIL

Rewrite the following code using PERFORM UNTIL instead of PERFORM VARYING:

           PERFORM VARYING WS-I FROM 100 BY -5
               UNTIL WS-I < 0
               DISPLAY WS-I
           END-PERFORM

Write a COBOL program that implements a binary search on a sorted array of 20 numbers. The program should: 1. Initialize a sorted array with values 5, 10, 15, 20, ..., 100. 2. Search for a target value (e.g., 65). 3. Use PERFORM UNTIL with a found-flag and converging low/high pointers. 4. Display each guess and whether it was too high, too low, or correct. 5. Display the number of comparisons made.


Exercise 15: Structured Program Skeleton

Design and write the PROCEDURE DIVISION skeleton (paragraph names and PERFORM statements only, no detailed logic) for a COBOL program that processes a customer order file and produces an invoice report. Your skeleton should include:

  • Main program paragraph (IPT pattern)
  • Initialization (open files, print headers)
  • Processing loop with priming read
  • Record validation
  • Order total calculation
  • Invoice line printing
  • Summary totals printing
  • File closing

Use descriptive paragraph names following the verb-noun naming convention.


Exercise 16: Inline vs. Out-of-Line Decision

For each scenario below, state whether you would use inline PERFORM or out-of-line PERFORM, and explain your reasoning:

a) Summing elements of a small 5-element array b) Validating 15 different fields of an input record c) A loop that reads and processes records until end-of-file d) Initializing 50 working storage variables to their default values e) A nested loop that fills a 100x100 matrix f) A loop body that is called from three different places in the program


Tier 3: Analysis and Problem Solving (Exercises 17-24)

These exercises require analyzing problems and designing complete solutions.


Exercise 17: Simple Control Break

Write a COBOL program that processes the following department expense data (already sorted by department) and produces a report with department subtotals and a grand total:

Department Amount
ACCT 1,500.00
ACCT 2,300.00
ACCT 1,800.00
ACCT 2,100.00
MGMT 4,500.00
MGMT 5,200.00
MGMT 4,800.00
SALE 3,200.00
SALE 2,800.00
SALE 3,500.00
SALE 3,100.00
SALE 2,900.00

Use the standard control break pattern with PERFORM UNTIL and a previous-key variable.


Exercise 18: Nested Loop Pattern -- Pyramid

Write a COBOL program that produces the following output using nested PERFORM VARYING loops:

    *
   ***
  *****
 *******
*********

The program should work for any height specified in a variable (e.g., WS-HEIGHT = 5). This requires computing the correct number of leading spaces and stars for each row.


Exercise 19: String Processing Loop

Write a COBOL program that accepts a string (up to 50 characters) and uses PERFORM VARYING to: 1. Count the number of vowels, consonants, digits, and other characters. 2. Convert all lowercase letters to uppercase. 3. Display the original string and the converted string. 4. Display the character counts.


Exercise 20: Powers of 2

Write a COBOL program that displays the powers of 2 from 2^0 through 2^20 using a PERFORM VARYING loop. Each line should show the exponent and the result. Verify that 2^10 = 1024 and 2^20 = 1048576.


Exercise 21: Sorting with PERFORM

Implement the selection sort algorithm using nested PERFORM VARYING loops. The program should: 1. Initialize an array with unsorted values: 64, 25, 12, 22, 11, 90, 34, 45. 2. Display the array before sorting. 3. Sort using selection sort (find minimum in remaining portion, swap with current position). 4. Display the array after each pass. 5. Display the final sorted array.


Exercise 22: Euclid's GCD Algorithm

Write a COBOL program that computes the Greatest Common Divisor (GCD) of two numbers using Euclid's algorithm with PERFORM UNTIL. The algorithm is: 1. Given two numbers A and B (A > B). 2. Replace A with B, and B with A mod B. 3. Repeat until B is zero. 4. A is the GCD.

Test with the pairs: (252, 105), (1071, 462), (100, 75).


Exercise 23: PERFORM VARYING with AFTER

Write a COBOL program that uses PERFORM VARYING ... AFTER to fill and display a 3x4 matrix where each element is the sum of its row index and column index (e.g., element [2,3] = 5). Display the matrix in a neat grid format.

Then use another PERFORM VARYING ... AFTER to compute the sum of each row and each column, displaying the results.


Exercise 24: Convert GO TO to PERFORM

Rewrite the following GO TO-based code using structured PERFORM statements (no GO TO):

       PROCESS-RECORDS.
           READ INPUT-FILE INTO WS-RECORD
               AT END GO TO PROCESS-END.
       PROCESS-LOOP.
           IF WS-RECORD-TYPE = 'H'
               GO TO PROCESS-NEXT.
           IF WS-AMOUNT < 0
               ADD 1 TO WS-ERROR-COUNT
               GO TO PROCESS-NEXT.
           ADD WS-AMOUNT TO WS-TOTAL
           ADD 1 TO WS-RECORD-COUNT
           WRITE OUTPUT-RECORD FROM WS-RECORD.
       PROCESS-NEXT.
           READ INPUT-FILE INTO WS-RECORD
               AT END GO TO PROCESS-END.
           GO TO PROCESS-LOOP.
       PROCESS-END.
           DISPLAY "Records: " WS-RECORD-COUNT.
           DISPLAY "Errors:  " WS-ERROR-COUNT.

Tier 4: Design and Synthesis (Exercises 25-32)

These exercises require designing complete programs with proper structured design.


Exercise 25: Complete Payroll Program

Design and implement a complete payroll program following the IPT pattern. The program should:

  1. Initialize: Set up employee data in a table (5 employees with name, hours, and hourly rate).
  2. Process: For each employee, calculate: - Regular pay (up to 40 hours) - Overtime pay (hours over 40 at 1.5x rate) - Gross pay (regular + overtime) - Tax (22% of gross) - Net pay (gross - tax)
  3. Terminate: Print a summary showing total gross pay and total net pay for all employees.

Use at least three levels of paragraph hierarchy. Include a paragraph for each calculation step.


Exercise 26: Grade Distribution Report

Write a COBOL program that processes an array of 50 student test scores (values between 0 and 100) and produces a grade distribution report:

  • A: 90-100
  • B: 80-89
  • C: 70-79
  • D: 60-69
  • F: below 60

Use PERFORM VARYING to iterate through scores, EVALUATE for grade assignment, and accumulator variables for each grade category. Display the count and percentage for each grade, plus the class average, highest score, and lowest score.


Exercise 27: Calendar Generator

Write a COBOL program that displays a calendar for a given month and year. The program should: 1. Accept month and year as data items. 2. Calculate the day of the week for the 1st of the month (Zeller's formula or similar). 3. Calculate the number of days in the month (handle leap years). 4. Display the calendar in a standard 7-column grid format with day-of-week headers.

Use PERFORM VARYING for the day loop and PERFORM UNTIL for the week loop.


Exercise 28: Multi-Level Report

Design and implement a sales report program that processes sales data organized by: - Region (3 regions: North, South, West) - Quarter (4 quarters) - Month (3 months per quarter)

Use a three-dimensional array and nested PERFORM VARYING loops to: 1. Calculate quarterly subtotals by region. 2. Calculate annual totals by region. 3. Calculate monthly totals across all regions. 4. Display a formatted report with all subtotals and grand totals.


Exercise 29: Menu-Driven Calculator

Write a COBOL program that implements a simple calculator using a menu-driven PERFORM WITH TEST AFTER loop:

  1. Display a menu: Add, Subtract, Multiply, Divide, Clear, Quit
  2. Accept the user's choice (simulate with a predefined sequence of operations).
  3. For arithmetic operations, accept two operands and display the result.
  4. For Clear, reset the accumulator.
  5. For Quit, display session summary (number of operations performed) and exit.

Structure the program using a clear paragraph hierarchy.


Exercise 30: Data Validation Framework

Write a COBOL program that validates customer records using a structured validation framework:

  1. Define a customer record with: customer ID, name, address, city, state, zip, phone, email indicator.
  2. Create a validation paragraph for each field.
  3. Use a master validation paragraph that PERFORMs each field validation.
  4. Track errors using an error counter and error message table.
  5. Process 5 sample records (some valid, some with various errors).
  6. Display a validation report showing which records passed and which failed, with specific error messages.

Exercise 31: Statistical Analysis

Write a COBOL program that performs statistical analysis on a dataset of 20 numbers using various PERFORM patterns:

  1. Mean: Use PERFORM VARYING to sum and divide.
  2. Median: Sort the array (using a sorting PERFORM loop), then find the middle value.
  3. Mode: Use nested PERFORM VARYING to count occurrences of each value.
  4. Standard deviation: Use PERFORM VARYING to compute the sum of squared differences from the mean.
  5. Range: Use PERFORM VARYING to find min and max.

Display all results with appropriate labels and formatting.


Exercise 32: Text Report Formatter

Write a COBOL program that takes a paragraph of text (stored as multiple 80-character lines) and reformats it to a specified line width (e.g., 60 characters). The program should:

  1. Read words from the input text using character-by-character scanning with PERFORM VARYING.
  2. Accumulate words into output lines, wrapping to the next line when a word would exceed the line width.
  3. Right-justify each completed line by distributing extra spaces between words.
  4. Display the formatted output.

This exercise combines string processing with multiple PERFORM patterns.


Tier 5: Critical Thinking and Evaluation (Exercises 33-40)

These exercises require critical analysis, comparison, and evaluation of different approaches.


Exercise 33: PERFORM THRU Analysis

A legacy COBOL program uses the following structure:

           PERFORM PROCESS-ORDER THRU PROCESS-ORDER-EXIT.

       PROCESS-ORDER.
           PERFORM VALIDATE-ORDER
           IF ORDER-VALID
               PERFORM CALCULATE-TOTAL
               PERFORM APPLY-DISCOUNT
           END-IF.

       GENERATE-INVOICE.
           PERFORM PRINT-INVOICE-HEADER
           PERFORM PRINT-INVOICE-LINES
           PERFORM PRINT-INVOICE-FOOTER.

       PROCESS-ORDER-EXIT.
           EXIT.

A maintenance programmer needs to add invoice generation for valid orders. They insert a PERFORM GENERATE-INVOICE into the PROCESS-ORDER paragraph. However, they notice that GENERATE-INVOICE is physically located between PROCESS-ORDER and PROCESS-ORDER-EXIT.

a) What happens when this code executes? Is GENERATE-INVOICE executed once or twice for valid orders? b) How would you restructure this code to avoid the THRU problem? c) What coding standards would prevent this issue?


Exercise 34: Performance Comparison

Consider these three implementations of the same logic -- summing all elements in a 10,000-element array:

      * Version A: Out-of-line PERFORM VARYING
           PERFORM SUM-ONE-ELEMENT
               VARYING WS-I FROM 1 BY 1
               UNTIL WS-I > 10000.
       SUM-ONE-ELEMENT.
           ADD WS-ARRAY(WS-I) TO WS-TOTAL.

      * Version B: Inline PERFORM VARYING
           PERFORM VARYING WS-I FROM 1 BY 1
               UNTIL WS-I > 10000
               ADD WS-ARRAY(WS-I) TO WS-TOTAL
           END-PERFORM

      * Version C: PERFORM UNTIL with manual counter
           MOVE 1 TO WS-I
           PERFORM UNTIL WS-I > 10000
               ADD WS-ARRAY(WS-I) TO WS-TOTAL
               ADD 1 TO WS-I
           END-PERFORM

a) Rank these three versions by likely performance (fastest to slowest) and explain why. b) Which version would you choose for production code and why? c) Under what circumstances (if any) would the performance difference matter?


Exercise 35: Loop Equivalence

Prove that the following two loops are NOT equivalent by finding input values where they produce different results:

      * Loop A: TEST BEFORE
           MOVE 1 TO WS-X
           PERFORM UNTIL WS-X > WS-N
               ADD WS-X TO WS-TOTAL
               ADD 1 TO WS-X
           END-PERFORM

      * Loop B: TEST AFTER
           MOVE 1 TO WS-X
           PERFORM WITH TEST AFTER
               UNTIL WS-X > WS-N
               ADD WS-X TO WS-TOTAL
               ADD 1 TO WS-X
           END-PERFORM

For what value(s) of WS-N do these produce different results? What are the different results?


Exercise 36: Structured Programming Debate

A colleague argues that the following GO TO pattern is clearer than the structured alternative for a paragraph with multiple validation checks:

      * GO TO version:
       VALIDATE-RECORD.
           IF WS-CUST-ID = SPACES
               MOVE "Missing customer ID" TO WS-ERROR
               GO TO VALIDATE-RECORD-EXIT.
           IF WS-AMOUNT NOT NUMERIC
               MOVE "Non-numeric amount" TO WS-ERROR
               GO TO VALIDATE-RECORD-EXIT.
           IF WS-DATE-FIELD NOT NUMERIC
               MOVE "Invalid date" TO WS-ERROR
               GO TO VALIDATE-RECORD-EXIT.
           SET RECORD-VALID TO TRUE.
       VALIDATE-RECORD-EXIT.
           EXIT.

a) Write the purely structured equivalent (no GO TO, no EXIT PARAGRAPH). b) Write the COBOL 2002+ equivalent using EXIT PARAGRAPH. c) Compare all three versions for readability, maintainability, and correctness. d) Which would you recommend for new code? For maintaining legacy code?


Exercise 37: PERFORM Stack Analysis

Trace the PERFORM stack for the following program. At each numbered comment, show the contents of the PERFORM stack (which return addresses are on it):

       MAIN.                           *> (1) Stack: ?
           PERFORM PARA-A
           STOP RUN.                    *> (6) Stack: ?

       PARA-A.                         *> (2) Stack: ?
           PERFORM PARA-B
           DISPLAY "Back in A".        *> (5) Stack: ?

       PARA-B.                         *> (3) Stack: ?
           PERFORM PARA-C
           DISPLAY "Back in B".        *> (4) Stack: ?

       PARA-C.
           DISPLAY "In C".

Exercise 38: Design Critique

Critique the following program structure. Identify at least five problems with the PERFORM organization:

       MAIN-PARA.
           PERFORM PARA-1
           PERFORM PARA-2 THRU PARA-5
           PERFORM PARA-6 100 TIMES
           PERFORM PARA-2
           STOP RUN.

       PARA-1.
           PERFORM PARA-3.
       PARA-2.
           MOVE 'A' TO WS-FLAG.
       PARA-3.
           PERFORM PARA-4.
       PARA-4.
           DISPLAY "Hello".
       PARA-5.
           EXIT.
       PARA-6.
           PERFORM PARA-6.

Exercise 39: Real-World Pattern Design

A bank processes daily transactions against customer accounts. Transactions are sorted by account number and then by transaction date. There are three transaction types:

  • D (Deposit): Add to balance
  • W (Withdrawal): Subtract from balance (reject if insufficient funds)
  • I (Interest): Calculate and add daily interest

Design the PROCEDURE DIVISION structure (paragraph names, PERFORM statements, and brief comments) for this program. Include: - IPT pattern at the top level - Control break on account number - Running balance tracking - Error handling for insufficient funds - Daily interest calculation - Account summary at each control break - Grand summary at end-of-file

Do not write the full implementation -- just the structural skeleton with PERFORM statements.


Exercise 40: Comprehensive Iteration Challenge

Write a COBOL program that demonstrates ALL forms of PERFORM in a single, cohesive application. The program should implement a simple student grade book that:

  1. Uses PERFORM paragraph to call initialization and cleanup routines.
  2. Uses PERFORM THRU (with EXIT paragraph) for a multi-step report generation process.
  3. Uses PERFORM TIMES to print a decorative border.
  4. Uses PERFORM UNTIL (TEST BEFORE) for the main processing loop.
  5. Uses PERFORM WITH TEST AFTER for input validation retry.
  6. Uses PERFORM VARYING to iterate through student records.
  7. Uses PERFORM VARYING with AFTER to process a 2D grade matrix (students x assignments).
  8. Uses Inline PERFORM for short calculations.
  9. Uses Nested out-of-line PERFORM for the report hierarchy.

The program should follow the IPT pattern with at least a three-level paragraph hierarchy. Include clear comments identifying which PERFORM form is being demonstrated in each section.


Solution Notes

Selected solutions are provided in code/exercise-solutions.cob. The solutions demonstrate best practices including:

  • Proper fixed-format column alignment
  • Meaningful data names following naming conventions
  • 88-level condition names for loop control
  • The IPT pattern for overall program structure
  • Comments explaining the approach

For exercises that ask for analysis or design (rather than code), sample answers are provided in the solution file comments and in-class discussion materials.