Section 1.16: Factorial Recursion#

Adapted from: “Guide to Fortran 2008 Programming” by Walter S. Brainerd (Springer 2015)

Program to calculate factorials using recursion in Fortran.#

module factorial_module

    implicit none
    public :: factorial

contains

    recursive function factorial(n) result (factorial_result)

        integer, intent(in) :: n
        integer :: factorial_result

        if (n <= 0) then
            factorial_result = 1
        else
            factorial_result = n * factorial(n - 1)
        end if

    end function factorial

end module factorial_module

program test_factorial
    
    use factorial_module
    implicit none

    integer :: n

    read *, n ! Will be piped in from command line
    print *
    write (unit = *, fmt = "(i10, a, i10)") n, "! = ", factorial(n)

end program test_factorial

The following explanation is given by “Code Copilot” within ChatGPT 4.

The provided Fortran program consists of two main components: a module named factorial_module and a program named test_factorial. Here is an explanation of each part and their interactions:

Module: factorial_module#

Purpose:#

The module defines and makes publicly available a recursive function factorial that computes the factorial of a given integer n. The factorial of a number is the product of all positive integers less than or equal to that number. It’s defined as:

  • \( n! = n \times (n-1) \times ... \times 2 \times 1 \)

  • \( 0! = 1 \) (by definition)

Structure:#

  • Function Declaration: The function factorial is declared as recursive, allowing it to call itself within its definition.

  • Parameters:

  • Input: n (integer) - the number for which the factorial is to be computed.

  • Output: factorial_result (integer) - the computed factorial value.

  • Logic:

  • If n is less than or equal to zero, the factorial is defined as 1. This also correctly handles the base case for the recursion.

  • Otherwise, the function computes the factorial by calling itself with n - 1 and multiplying the result by n.

Program: test_factorial#

Purpose:#

This program uses the factorial function defined in the factorial_module to compute the factorial of an integer read from the command line.

Structure:#

  • Module Usage: It includes the factorial_module using the use statement to access the factorial function.

  • Input Handling: Reads an integer n from the standard input. In the given context, this input is expected to be piped in from the command line.

  • Output: Prints the result of the factorial computation in a formatted string showing n and n!.

Execution Flow:#

  1. Compilation and Linking:

  • The factorial_module is compiled first to ensure that the definition of the factorial function is available.

  • The test_factorial program is compiled and linked with the factorial_module.

  1. Running:

  • The program expects an integer input from the command line.

  • It computes the factorial of the input integer using the factorial function.

  • It outputs the result in the format “n! = result”.

Conclusion:#

This Fortran setup efficiently demonstrates modular programming by separating the mathematical logic (factorial computation) into a module for reuse. The recursive function is a straightforward and classic implementation for calculating factorials, suitable for small to moderately large values of n due to potential stack overflow issues with very large recursion depths. The program is well-structured for educational purposes and basic computational tasks involving factorials.

Program Compilation and Execution#

The above program is compiled and run using Fortran Package Manager (fpm):

import os
root_dir = os.getcwd()
code_dir = root_dir + "/" + "Fortran_Code/Section_1_16_Factorial_Recursion"
os.chdir(code_dir)
build_status = os.system("fpm build 2>/dev/null")

Calculate:#

\[ \Large 3! \]
exec_status = os.system("echo 3 | fpm run 2>/dev/null")
         3! =          6

Calculate:#

\[ \Large 6! \]
exec_status = os.system("echo 6 | fpm run 2>/dev/null")
         6! =        720

Calculate:#

\[ \Large 15! \]
exec_status = os.system("echo 15 | fpm run 2>/dev/null")
        15! = 2004310016