Pascals Triangle in Cobol: Complete Solution & Deep Dive Guide

two blue triangle logos

Mastering Pascal's Triangle in Cobol: The Complete Guide

Generating Pascal's Triangle in COBOL is a classic algorithmic challenge that involves using fixed-size arrays, known as tables, and nested loops. The core logic iterates through rows, calculating each new element by summing the two corresponding elements from the previously computed row, while carefully handling the '1's that form the triangle's edges.

Ever looked at COBOL code and felt like you were deciphering an ancient scroll? You're not alone. For many modern developers, COBOL's verbose, structured syntax can seem intimidating, a relic from a bygone era of mainframes and magnetic tape. It's easy to dismiss it as a language incapable of the elegant algorithmic solutions we build in Python or JavaScript.

But what if we could bridge that gap? What if you could take a familiar mathematical pattern, Pascal's Triangle, and build it from the ground up in one of the most foundational programming languages ever created? This guide promises to do just that. We will demystify COBOL's structure and syntax, showing you how to implement this beautiful algorithm with surprising clarity and logic. Prepare to see COBOL not as a historical artifact, but as a powerful, structured tool for problem-solving.


What Exactly is Pascal's Triangle?

Before diving into the COBOL implementation, it's crucial to understand the "what" and "why" behind Pascal's Triangle. At its heart, Pascal's Triangle is a geometric arrangement of numbers in a triangular shape that holds a treasure trove of mathematical properties. It's named after the French mathematician Blaise Pascal, although mathematicians in India, Persia, and China had studied it centuries before him.

The Core Rule of Construction

The construction of the triangle follows a very simple, recursive rule:

  1. The triangle starts at the top (Row 0) with a single number: 1.
  2. Each subsequent row begins and ends with a 1.
  3. Every other number in a row is the sum of the two numbers directly above it in the previous row.

Visually, it looks like this:

        1
       1 1
      1 2 1
     1 3 3 1
    1 4 6 4 1
   1 5 10 10 5 1

Each number in the triangle is a binomial coefficient. The number at row n and position k (both zero-indexed) corresponds to the value of "n choose k," written as C(n, k). This is the number of ways to choose k items from a set of n items, a fundamental concept in combinatorics and probability.


Why Tackle This Algorithm in COBOL?

You might be wondering, "Why use a language from the 1950s for a math problem I can solve in three lines of Python?" The answer lies in the unique educational value and the deep understanding of computing fundamentals that COBOL provides.

  • Mastering Data Structures: COBOL forces you to be explicit about data. You must declare fixed-size tables (its version of arrays) in the DATA DIVISION. This exercise provides an excellent practical lesson in managing array indices and manipulating data within a predefined memory structure, a skill that is surprisingly relevant in performance-critical systems today.
  • Understanding Procedural Logic: Modern languages often hide complexity behind high-level abstractions. COBOL's procedural nature, with its PERFORM statements and structured paragraphs, makes the program's flow of control crystal clear. You build the logic block by block, reinforcing a disciplined, structured programming mindset.
  • Legacy System Insight: Billions of lines of COBOL code still run critical systems in finance, insurance, and government. Understanding how to read, maintain, and write algorithmic COBOL code is a valuable and surprisingly niche skill. This module from the kodikra learning path is designed to build that exact competency.
  • Demystifying the "Magic": By building Pascal's Triangle in COBOL, you are forced to manage the state of the "previous row" and "current row" manually. This peels back the layers of abstraction and gives you a much deeper appreciation for how more modern languages handle iterators and data transformations under the hood.

How to Implement Pascal's Triangle in COBOL: A Deep Dive

Now, let's get to the main event: building the solution. We will break down the process step-by-step, from setting up the program structure to writing the final line of procedural logic. Our approach will use two arrays: one to hold the values of the previous row and one to compute the values for the current row.

The COBOL Program Structure: The Four Divisions

Every COBOL program is rigidly structured into four divisions, each with a specific purpose:

  1. IDENTIFICATION DIVISION: Metadata about the program, like its name (PROGRAM-ID) and author.
  2. ENVIRONMENT DIVISION: Describes the environment in which the program will run. For our simple console application, this section is minimal.
  3. DATA DIVISION: This is where we declare all our variables, constants, and data structures. It's the heart of our program's memory layout.
  4. PROCEDURE DIVISION: Contains the executable code—the logic, loops, and calculations that bring the program to life.

Step 1: Defining Our Data in the WORKING-STORAGE SECTION

Inside the DATA DIVISION, the WORKING-STORAGE SECTION is where we'll define the variables needed to generate the triangle. We need variables for loop counters, a display line, and most importantly, the tables to hold the triangle's rows.


DATA DIVISION.
WORKING-STORAGE SECTION.
01 Ws-Control-Variables.
   05 Ws-Max-Rows             PIC 9(02) VALUE 10.
   05 Ws-Current-Row-Num       PIC 9(02).
   05 Ws-Col-Num               PIC 9(02).
   05 Ws-Prev-Col-Num          PIC 9(02).

01 Ws-Pascal-Triangle-Data.
   05 Ws-Previous-Row.
      10 Ws-Prev-Element       PIC 9(05) OCCURS 20 TIMES.
   05 Ws-Current-Row.
      10 Ws-Curr-Element       PIC 9(05) OCCURS 20 TIMES.

01 Ws-Formatting-Fields.
   05 Ws-Display-Element       PIC Z(4)9.
   05 Ws-Display-Row           PIC X(80).
   05 Ws-Padding-Spaces        PIC X(01) VALUE SPACE.

Let's break this down:

  • Ws-Control-Variables: A group item for our loop counters. Ws-Max-Rows determines how many rows of the triangle to generate. PIC 9(02) defines a two-digit numeric variable.
  • Ws-Pascal-Triangle-Data: This is our core data structure.
    • Ws-Previous-Row and Ws-Current-Row are our two arrays (tables).
    • The OCCURS 20 TIMES clause is how you declare an array in COBOL. It creates 20 instances of Ws-Prev-Element and Ws-Curr-Element.
    • PIC 9(05) means each element can hold a 5-digit number, which is enough for the first 20 rows of the triangle.
  • Ws-Formatting-Fields: These variables help us create a nicely formatted output string. PIC Z(4)9 is a numeric-edited field that suppresses leading zeros.

Step 2: The Logical Flow in the PROCEDURE DIVISION

The PROCEDURE DIVISION is where our algorithm is executed. Good COBOL practice involves breaking logic into reusable paragraphs (similar to functions or methods) and calling them with the PERFORM verb.

Our main logic will be a loop that iterates from row 1 up to Ws-Max-Rows. In each iteration, it will:

  1. Calculate the new current row based on the previous row.
  2. Display the newly calculated row.
  3. Copy the current row's data into the previous row's table to prepare for the next iteration.

Here is an ASCII art diagram illustrating this high-level program flow:

    ● Start
    │
    ▼
  ┌───────────────────┐
  │ Initialize Tables │
  │ (Move Zeros)      │
  └─────────┬─────────┘
            │
            ▼
  ┌───────────────────┐
  │ Loop through Rows │
  │ (1 to Max-Rows)   │
  └─────────┬─────────┘
            │
    ╭───────╯
    │
    ▼
  ┌────────────────────┐
  │ Calculate New Row  │
  │ From Previous Row  │
  └──────────┬─────────┘
             │
             ▼
  ┌────────────────────┐
  │ Display Formatted  │
  │      New Row       │
  └──────────┬─────────┘
             │
             ▼
  ┌────────────────────┐
  │ Copy Current Row   │
  │ to Previous Row    │
  └──────────┬─────────┘
             │
    ╰───────╮
            │
            ▼
    ● End Program

Step 3: The Core Calculation Logic

The most interesting part is the paragraph that calculates the new row. It uses an inner loop to iterate through the columns of the new row.

The logic follows these rules:

  • The first element of any row is always 1.
  • For any other element at column j, its value is Previous-Row[j-1] + Previous-Row[j].
  • The last element of the row (at column i for row i) is also always 1.

Let's visualize how the indices of the arrays are used to calculate Row 4 from Row 3:

  Previous Row (Row 3): [ 1, 3, 3, 1, 0, ... ]
                          │  │  │  │
                          │  └─┼──┼─┘
                          └──┬─┼─┘
                             │ │
                             ▼ ▼
  Calculation:            (1+3) (3+3) (3+1)
                             │     │     │
                             ▼     ▼     ▼
  Current Row (Row 4):  [ 1, 4,    6,    4,   1, 0, ... ]

This ASCII diagram shows the data flow for the calculation logic:

    ● Start Row Calculation
    │
    ▼
  ┌─────────────────────────┐
  │ Set First Element to 1  │
  │ Curr-Element(1) = 1     │
  └───────────┬─────────────┘
              │
              ▼
  ┌─────────────────────────┐
  │ Loop Columns (2 to N)   │
  └───────────┬─────────────┘
              │
      ╭───────╯
      │
      ▼
  ┌─────────────────────────┐
  │ Add Prev-Element(Col-1) │
  │ and Prev-Element(Col)   │
  └───────────┬─────────────┘
              │
              ▼
  ┌─────────────────────────┐
  │ Store in Curr-Element(Col)│
  └───────────┬─────────────┘
              │
      ╰───────╮
              │
              ▼
  ┌─────────────────────────┐
  │ Set Last Element to 1   │
  │ Curr-Element(N) = 1     │
  └───────────┬─────────────┘
              │
              ▼
    ● End Row Calculation

The Complete COBOL Solution

Putting it all together, here is the full, well-commented source code. This code is designed to be compiled with a modern compiler like GnuCOBOL.


******************************************************************
* Program: PascalsTriangle
* Author:  Kodikra.com
*
* This program generates and displays the first N rows of
* Pascal's Triangle. It is part of the exclusive kodikra.com
* learning curriculum.
*
* The logic uses two tables (arrays): one for the previous row
* and one for the current row being calculated. This avoids
* the need for a 2D array, simplifying the logic.
******************************************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. PascalsTriangle.
AUTHOR. Kodikra.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.

******************************************************************
* DATA DIVISION: All variables and data structures are defined here.
******************************************************************
DATA DIVISION.
FILE SECTION.

WORKING-STORAGE SECTION.
*== Group for control variables like loop counters and limits ==*
01 Ws-Control-Variables.
   05 Ws-Max-Rows             PIC 9(02) VALUE 10.
   05 Ws-Current-Row-Num       PIC 9(02).
   05 Ws-Col-Num               PIC 9(02).
   05 Ws-Prev-Col-Num          PIC 9(02).

*== Group for the core data tables (arrays) for the triangle ==*
01 Ws-Pascal-Triangle-Data.
   05 Ws-Previous-Row.
      10 Ws-Prev-Element       PIC 9(05) OCCURS 20 TIMES.
   05 Ws-Current-Row.
      10 Ws-Curr-Element       PIC 9(05) OCCURS 20 TIMES.

*== Group for variables used to format the output string ==*
01 Ws-Formatting-Fields.
   05 Ws-Display-Element       PIC Z(4)9.
   05 Ws-Display-Row           PIC X(80).
   05 Ws-Padding-Spaces        PIC X(01) VALUE SPACE.


******************************************************************
* PROCEDURE DIVISION: Contains all the executable logic.
******************************************************************
PROCEDURE DIVISION.
Main-Procedure.
    *> Initialize the tables to ensure a clean state.
    PERFORM 100-Initialize-Triangle.

    *> Main loop to generate each row of the triangle.
    PERFORM 200-Generate-Triangle
        VARYING Ws-Current-Row-Num FROM 1 BY 1
        UNTIL Ws-Current-Row-Num > Ws-Max-Rows.

    *> End the program.
    STOP RUN.

*--- This paragraph resets the data tables to zero.
100-Initialize-Triangle.
    MOVE ZEROS TO Ws-Previous-Row.
    MOVE ZEROS TO Ws-Current-Row.

*--- This is the main control paragraph for each row's lifecycle.
200-Generate-Triangle.
    *> Step 1: Calculate the elements of the current row.
    PERFORM 300-Calculate-Current-Row.

    *> Step 2: Display the newly calculated row.
    PERFORM 400-Display-Current-Row.

    *> Step 3: The current row now becomes the previous row for the next iteration.
    MOVE Ws-Current-Row TO Ws-Previous-Row.
    MOVE ZEROS TO Ws-Current-Row. *> Clear current row for safety.

*--- This paragraph contains the core mathematical logic.
300-Calculate-Current-Row.
    *> The first element of every row is always 1.
    MOVE 1 TO Ws-Curr-Element(1).

    *> Loop from the second element up to the second-to-last.
    PERFORM VARYING Ws-Col-Num FROM 2 BY 1
    UNTIL Ws-Col-Num > Ws-Current-Row-Num
        *> Calculate the index for the previous row's first element.
        SUBTRACT 1 FROM Ws-Col-Num GIVING Ws-Prev-Col-Num

        *> The core formula: C(n,k) = C(n-1, k-1) + C(n-1, k)
        ADD Ws-Prev-Element(Ws-Prev-Col-Num)
            Ws-Prev-Element(Ws-Col-Num)
            GIVING Ws-Curr-Element(Ws-Col-Num)
    END-PERFORM.

    *> The last element of a row is also 1 (unless it's the very first row).
    IF Ws-Current-Row-Num > 1
        MOVE 1 TO Ws-Curr-Element(Ws-Current-Row-Num)
    END-IF.

*--- This paragraph formats and prints a single row to the console.
400-Display-Current-Row.
    MOVE SPACES TO Ws-Display-Row.

    *> This loop builds a single string from the numeric elements.
    PERFORM VARYING Ws-Col-Num FROM 1 BY 1
    UNTIL Ws-Col-Num > Ws-Current-Row-Num
        *> Move numeric element to a formatted field to handle spacing.
        MOVE Ws-Curr-Element(Ws-Col-Num) TO Ws-Display-Element

        *> Concatenate the formatted number and a space into the display line.
        STRING Ws-Display-Element DELIMITED BY SIZE
               Ws-Padding-Spaces DELIMITED BY SIZE
               INTO Ws-Display-Row
        END-STRING
    END-PERFORM.

    *> Display the final string, trimming any trailing spaces.
    DISPLAY FUNCTION TRIM(Ws-Display-Row).

END PROGRAM PascalsTriangle.

Step 4: Compiling and Running the Code

To see your COBOL program in action, you'll need a compiler. GnuCOBOL is a popular, free, and open-source option. Once installed, you can compile and run your program from the terminal.

1. Save the code above into a file named pascals_triangle.cbl.

2. Open your terminal or command prompt and navigate to the directory where you saved the file.

3. Compile the program using the following command:


cobc -x -free pascals_triangle.cbl
  • -x tells the compiler to create an executable file.
  • -free specifies that we are using a modern, free-format source code layout (not the rigid column-based layout of old COBOL).

4. If the compilation is successful, an executable file (pascals_triangle on Linux/macOS or pascals_triangle.exe on Windows) will be created.

5. Run the program:


./pascals_triangle

You should see the first 10 rows of Pascal's Triangle printed neatly to your console!


Pros and Cons of This COBOL Approach

Every implementation choice has trade-offs. While this COBOL solution is robust and educational, it's important to understand its strengths and weaknesses compared to implementations in other languages.

Pros Cons
Extreme Clarity: The verbose nature of COBOL and the strict separation of data and logic make the program's intent exceptionally clear and easy to follow for maintenance. Verbosity: What provides clarity can also be a drawback. The amount of code required is significantly higher than in languages like Python or Ruby.
Performance: Compiled COBOL is highly optimized for the kind of batch processing and numeric computation seen in this problem. It's fast and efficient. Static Data Structures: The use of fixed-size tables (OCCURS 20 TIMES) means our program has a hard limit. Generating a larger triangle would require recompiling the code with a larger table size.
Excellent for Learning Fundamentals: It forces a deep understanding of memory allocation (via the DATA DIVISION), array indexing, and structured procedural flow. Complex String Manipulation: Formatting the output requires using the STRING verb and helper variables, which is less intuitive than the string interpolation or formatting functions in modern languages.
High Reliability: The strict data typing and structured nature of COBOL lead to highly predictable and reliable programs, which is why it's trusted in critical financial systems. Steeper Initial Learning Curve: The rigid syntax, division structure, and specific verbs can be challenging for developers accustomed to more flexible modern languages.

Frequently Asked Questions (FAQ)

What is the `OCCURS` clause in COBOL?

The OCCURS clause is the fundamental way to define an array, or what COBOL calls a "table." When you write PIC 9(05) OCCURS 20 TIMES, you are telling the compiler to allocate a contiguous block of memory for 20 elements, each of which is a 5-digit number. You access elements using a subscript in parentheses, like Ws-Curr-Element(5).

Can I create Pascal's Triangle with a single array in COBOL?

Yes, it's possible but more complex. A single-array approach involves calculating the new row "in-place." To do this correctly, you must iterate through the array backward (from right to left). This prevents the newly calculated values from overwriting the old values that are still needed for the next calculation in the same row. Our two-array solution is generally easier to read and understand.

Why is my output formatting misaligned for larger numbers?

Formatting issues usually stem from the PICTURE clause of your display variables. In our example, PIC Z(4)9 and the single padding space are designed for numbers up to 5 digits. If your triangle grows large enough to have 6-digit numbers, they will push the subsequent numbers out of alignment. You would need to adjust the PICTURE clause (e.g., PIC Z(5)9) and potentially add more padding spaces in the STRING operation.

What is the difference between `COMPUTE` and `ADD`?

ADD is a specific verb for addition (e.g., ADD A TO B GIVING C). COMPUTE is a more general-purpose verb for arithmetic expressions. We could have replaced our ADD statement with COMPUTE Ws-Curr-Element(Ws-Col-Num) = Ws-Prev-Element(Ws-Prev-Col-Num) + Ws-Prev-Element(Ws-Col-Num). For simple addition, ADD is often considered more readable and traditional in COBOL, while COMPUTE is better for complex formulas involving multiple operations.

Is COBOL still a relevant language to learn?

Absolutely. While it's not used for new web or mobile apps, it powers the core systems of the global economy. Banks, insurance companies, and government agencies rely on COBOL mainframes. There is a high demand for developers who can maintain and modernize these critical legacy systems, making it a stable and lucrative career path. For a deeper look, you can explore our comprehensive guide to the COBOL language.

How would I accept the number of rows as user input?

To accept user input, you would define a variable in WORKING-STORAGE for the input, and then in the PROCEDURE DIVISION, you would use the ACCEPT Ws-UserInput-Rows verb. This would pause the program and wait for the user to type a value and press Enter. You would then use this variable instead of the hardcoded VALUE 10 in Ws-Max-Rows.


Conclusion: Timeless Logic in a Classic Language

We've successfully journeyed from the mathematical theory of Pascal's Triangle to a complete, working implementation in COBOL. In doing so, we've seen that despite its age and verbosity, COBOL is a powerful tool for executing structured, algorithmic logic. The strict separation of data and procedure, the explicit memory management, and the clear control flow are not just relics of the past; they are foundational programming principles that enforce clarity and reliability.

This exercise from the kodikra.com curriculum demonstrates that learning COBOL is more than just learning a new syntax. It's about connecting with the history of computing and understanding the fundamental building blocks that make modern software possible. The skills you've practiced here—manipulating tables, managing loops, and structuring procedural code—are timeless.

Disclaimer: The solution and code snippets in this article were developed and tested using GnuCOBOL 3.1.2. While the core logic is standard, specific syntax or compiler directives may differ when using other compilers such as IBM Enterprise COBOL for z/OS or Micro Focus Visual COBOL.

Ready to continue your journey? Explore the next module in our COBOL 5 roadmap and tackle even more challenging problems.


Published by Kodikra — Your trusted Cobol learning resource.