Fortran, one of the earliest high-level programming languages, was specifically designed for numerical and scientific computation. To write modular, maintainable, and reusable code, Fortran provides functions and subroutines. These two constructs allow programmers to organize programs into logical blocks that perform specific tasks. Understanding the differences between functions and subroutines and how to implement them is fundamental to effective Fortran programming.
This post provides an in-depth discussion on functions, subroutines, their differences, and practical examples of their usage.
1. Introduction to Functions and Subroutines
In Fortran, functions and subroutines are both procedures, but they serve slightly different purposes:
- Function: A function is a procedure that returns a single value. It is typically used when a computation needs to produce a value that can be assigned to a variable or used in expressions.
- Subroutine: A subroutine is a procedure that performs a specific task but does not return a value directly. Subroutines can modify variables via arguments and are often used for tasks like printing, input/output, or performing operations on arrays.
Breaking a program into functions and subroutines makes it easier to read, debug, and reuse code.
2. Difference Between Functions and Subroutines
| Feature | Function | Subroutine |
|---|---|---|
| Return Value | Returns a single value | Does not return a value directly |
| Usage in Expressions | Can be used in expressions | Cannot be used in expressions |
| Declaration | function function_name(arguments) | subroutine subroutine_name(arguments) |
| Invocation | Called by using its name in expressions | Called using the call statement |
| Example Use | Computing square, cube, trigonometric values | Printing a message, modifying arrays, performing repeated tasks |
3. Creating and Using Functions
Functions in Fortran are designed to perform calculations and return a value. The syntax for a function is:
function function_name(arguments)
data_type :: function_name, argument1, argument2, ...
! Body of the function
function_name = expression
end function function_name
Key Points:
- The function name must match the return variable.
- Arguments can be optional, but all must have declared types.
- Functions return exactly one value.
3.1 Example: Square Function
The following example defines a function that calculates the square of a number.
program test_square
real :: result
result = square(3.0)
print *, "Square of 3 =", result
contains
function square(x)
real :: square, x
square = x * x
end function square
end program test_square
Explanation:
- The
squarefunction takes one real argumentx. - It computes the square of
xand returns the result. - The
containsblock is used in modern Fortran to define internal functions.
3.2 Function with Multiple Arguments
Functions can also accept multiple arguments.
program test_average
real :: result
result = average(10.0, 20.0, 30.0)
print *, "Average =", result
contains
function average(a, b, c)
real :: average, a, b, c
average = (a + b + c) / 3.0
end function average
end program test_average
Explanation:
- The
averagefunction takes three real numbers as input. - It calculates and returns their average.
- Functions make computations reusable in different parts of the program.
3.3 Function Returning Integer Values
Functions can also return integer values:
program test_factorial
integer :: result
result = factorial(5)
print *, "Factorial of 5 =", result
contains
function factorial(n)
integer :: factorial, n, i
factorial = 1
do i = 1, n
factorial = factorial * i
end do
end function factorial
end program test_factorial
Explanation:
- The
factorialfunction calculates the factorial of an integern. - The return value is of type
integer. - The loop multiplies all numbers from 1 to
nto compute the factorial.
4. Creating and Using Subroutines
Subroutines in Fortran are designed to perform tasks that may not return a value directly but can modify variables passed to them. Subroutines are invoked using the call statement.
Syntax:
subroutine subroutine_name(arguments)
data_type :: argument1, argument2, ...
! Body of the subroutine
end subroutine subroutine_name
Key Points:
- Arguments passed to subroutines can be modified within the subroutine.
- Subroutines are called using the
callkeyword. - Subroutines are often used for input/output operations, data processing, or repetitive tasks.
4.1 Example: Greeting Subroutine
program test_greet
call greet("Alice")
call greet("Bob")
contains
subroutine greet(name)
character(len=20) :: name
print *, "Hello,", name
end subroutine greet
end program test_greet
Explanation:
- The
greetsubroutine prints a greeting message. - It accepts a character argument
nameand prints “Hello, [name]”. - The subroutine is invoked using
call greet("Alice").
4.2 Subroutine Modifying Variables
Subroutines can change the values of variables passed as arguments:
program test_square_sub
real :: num, result
num = 4.0
call compute_square(num, result)
print *, "Square of", num, "=", result
contains
subroutine compute_square(x, y)
real :: x, y
y = x * x
end subroutine compute_square
end program test_square_sub
Explanation:
compute_squareis a subroutine that calculates the square ofxand stores it iny.- Unlike functions, subroutines do not return a value but can modify multiple variables.
4.3 Subroutine with Multiple Arguments
program test_statistics
real :: a, b, mean, diff
a = 10.0
b = 20.0
call calculate_stats(a, b, mean, diff)
print *, "Mean =", mean
print *, "Difference =", diff
contains
subroutine calculate_stats(x, y, avg, delta)
real :: x, y, avg, delta
avg = (x + y) / 2.0
delta = x - y
end subroutine calculate_stats
end program test_statistics
Explanation:
- The
calculate_statssubroutine takes two numbers as input. - It calculates the mean and difference and assigns them to
avganddelta.
5. Internal vs External Procedures
5.1 Internal Procedures
Internal procedures are defined within a program or module using the contains statement. Examples above, like square and greet, are internal procedures.
Advantages:
- Access to program variables.
- Encapsulation and readability.
5.2 External Procedures
External procedures are defined outside the main program or module and linked during compilation.
Example:
! file: myfunctions.f90
function cube(x)
real :: cube, x
cube = x**3
end function cube
program test_cube
real :: result
result = cube(3.0)
print *, "Cube of 3 =", result
end program test_cube
Compilation Command:
gfortran myfunctions.f90 test_cube.f90 -o test_cube
Explanation:
- The function
cubeis external to the main program. - It is compiled along with the main program to produce the executable.
6. Modules for Functions and Subroutines
Modules allow grouping functions and subroutines together for reusability.
Example:
module math_operations
contains
function square(x)
real :: square, x
square = x * x
end function square
subroutine greet(name)
character(len=20) :: name
print *, "Hello,", name
end subroutine greet
end module math_operations
program test_module
use math_operations
real :: result
result = square(5.0)
print *, "Square of 5 =", result
call greet("Charlie")
end program test_module
Explanation:
- The
math_operationsmodule contains both a function and a subroutine. - The main program uses the module to access its procedures.
7. Best Practices for Functions and Subroutines
- Use descriptive names that indicate their purpose.
- Keep functions focused on computing a single value.
- Use subroutines for tasks that involve multiple variables or I/O operations.
- Use
implicit nonein procedures to avoid undeclared variables. - Document the arguments and return values clearly.
- Prefer modules for grouping related procedures for better code organization.
8. Summary
- Functions return a single value and can be used in expressions.
- Subroutines do not return values directly but can modify arguments.
- Functions and subroutines enhance code reusability, readability, and modularity.
- Modern Fortran encourages the use of modules and internal procedures.
- Proper use of arguments, return values, and meaningful names leads to maintainable programs.
9. Complete Example: Using Both Functions and Subroutines
module utilities
contains
function square(x)
real :: square, x
square = x * x
end function square
subroutine greet(name)
character(len=20) :: name
print *, "Hello,", name
end subroutine greet
function factorial(n)
integer :: factorial, n, i
factorial = 1
do i = 1, n
factorial = factorial * i
end do
end function factorial
end module utilities
program main_program
use utilities
real :: num
integer :: n
character(len=20) :: person
num = 6.0
print *, "Square of", num, "=", square(num)
n = 5
print *, "Factorial of", n, "=", factorial(n)
person = "Alice"
call greet(person)
end program main_program
Explanation:
- The module
utilitiescontains a functionsquare, a subroutinegreet, and a functionfactorial. - The main program uses the module and demonstrates the usage of functions and subroutines.
Leave a Reply