🔬 Introduction to the Fortran Programming Language

Andrew J. Pounds, Ph.D.

🎯 Learning Objectives

After completing this exercise, you will be able to:

1️⃣ What is Fortran?

Fortran (FORmula TRANslation) is one of the oldest high-level programming languages, originally developed by IBM in 1957 under the leadership of John Backus. It was designed specifically for scientific and engineering computation and remains widely used in high-performance computing, computational physics, climate modeling, and numerical analysis.

Fortran has evolved significantly over the decades:

Fortran supports multiple programming paradigms including:

Fortran source files typically use the .f90 or .f95 extension for free-form code. We will use the GNU Fortran Compiler (GFortran), which is part of the GCC compiler collection.

2️⃣ Your First Fortran Program

Create a file called hello.f90 with the following content:

program hello
    implicit none
    print *, "Hello, World!"
end program hello

Compiling and Running

Open a terminal and navigate to the directory containing your file. Compile and run with:

gfortran hello.f90 -o hello
./hello

You should see Hello, World! printed to the console.

If you omit the -o hello option, GFortran will create an executable called a.out by default.

Understanding the Code

Code Element Explanation
program hello Declares the start of the main program unit named "hello"
implicit none Disables implicit typing; all variables must be explicitly declared
print *, ... Writes output to the console using list-directed formatting
end program hello Marks the end of the program unit

3️⃣ Variable Types

Fortran is a statically typed language, meaning you must declare the type of each variable. Fortran provides several fundamental types:

Implicit Typing (Historical Behavior)

By default, Fortran uses implicit typing based on the first letter of a variable name:

First Letter Implicit Type
I, J, K, L, M, N integer
A-H, O-Z real

This means you could write:

program implicit_example
    ! Without implicit none, these are automatically typed:
    ! index is integer (starts with 'i')
    ! value is real (starts with 'v')
    index = 10
    value = 3.14
    print *, index, value
end program implicit_example
Warning: Implicit typing is dangerous! A simple typo creates a new variable instead of causing an error. For example, if you accidentally type valeu instead of value, Fortran silently creates a new variable initialized to zero.

The implicit none Statement

The implicit none statement disables implicit typing and requires explicit declaration of all variables:

program safe_example
    implicit none
    integer :: index
    real :: value
    
    index = 10
    value = 3.14
    print *, index, value
end program safe_example
Best Practice: Always use implicit none at the beginning of every program unit. This catches typos at compile time and makes your code self-documenting.

Integer Types

Declaration Description
integer Default integer (typically 32 bits)
integer(kind=2) Short integer (typically 16 bits)
integer(kind=4) Standard integer (typically 32 bits)
integer(kind=8) Long integer (typically 64 bits)

Floating-Point Types

Declaration Description
real Default real (typically 32 bits, ~7 significant digits)
real(kind=8) or double precision Double precision (~15 significant digits)
real(kind=16) Quad precision (if supported by compiler)

Other Fundamental Types

Type Description Example
logical Boolean (.true. or .false.) logical :: flag = .true.
character Single character or string character :: letter = 'A'
character(len=20) Fixed-length string character(len=20) :: name = "Alice"
complex Complex number complex :: z = (1.0, 2.0)

Variable Declaration Examples

program variables
    implicit none
    
    ! Explicit type declarations
    integer :: age = 25
    real :: gpa = 3.85
    double precision :: pi = 3.141592653589793d0
    character(len=20) :: name = "Alice"
    logical :: enrolled = .true.
    
    ! Multiple variables on one line
    integer :: x, y, z
    real :: temperature, pressure
    
    ! Constants (cannot be changed)
    real, parameter :: GRAVITY = 9.81
    
    print *, "Name: ", trim(name)
    print *, "Age: ", age
    print *, "GPA: ", gpa
    print *, "Enrolled: ", enrolled
    print *, "Gravity constant: ", GRAVITY
end program variables

4️⃣ Console Output

Fortran provides several ways to produce output:

Statement Description
print *, items List-directed output to screen
print '(format)', items Formatted output to screen
write(*,*) items List-directed output to standard output
write(*,'(format)') items Formatted output to standard output
program output_demo
    implicit none
    integer :: x = 42
    real :: price = 19.99
    character(len=10) :: item = "widget"
    
    ! List-directed output (simplest)
    print *, "The answer is", x
    
    ! Multiple values
    print *, "Item: ", trim(item), ", Price: $", price
    
    ! Formatted output
    print '(A, I5)', "The answer is: ", x
    print '(A, A, A, F7.2)', "The ", trim(item), " costs $", price
    print '(A, I5.5)', "Zero-padded: ", x
    
    ! Using write statement
    write(*,*) "Using write statement"
    write(*,'(A, F10.4)') "Pi approximately: ", 3.14159
end program output_demo

Common Format Specifiers

Specifier Description Example
Iw Integer with width w I5 → 42
Iw.m Integer, minimum m digits I5.3 → 042
Fw.d Real with width w, d decimals F8.2 → 19.99
Ew.d Scientific notation E12.4 → 0.1999E+02
A Character string (auto width) A → widget
Aw Character string with width w A10 → widget
X Single space 1X
nX n spaces 5X
/ New line /

Formatted Output Examples

program format_examples
    implicit none
    integer :: i = 42
    real :: r = 3.14159
    character(len=10) :: s = "Fortran"
    
    ! Basic formats
    print '(A, I4)', "Integer: ", i
    print '(A, F8.3)', "Real: ", r
    print '(A, E12.4)', "Scientific: ", r
    print '(A, A)', "String: ", trim(s)
    
    ! Combined format with spacing
    print '(A, I3, A, F6.2)', "Value ", i, " and ", r
    
    ! Multiple items with repeat count
    print '(3I5)', 10, 20, 30
    print '(A, 3(I3, 1X))', "Numbers: ", 1, 2, 3
end program format_examples

5️⃣ Console Input

Reading input in Fortran uses the read statement:

program input_demo
    implicit none
    character(len=50) :: name
    integer :: age
    real :: gpa
    
    ! Reading a string
    print *, "Enter your name: "
    read '(A)', name
    
    ! Reading an integer
    print *, "Enter your age: "
    read *, age
    
    ! Reading a real
    print *, "Enter your GPA: "
    read *, gpa
    
    print '(A, A)', "Hello, ", trim(name)
    print '(A, I3, A, F5.2)', "Age: ", age, ", GPA: ", gpa
end program input_demo

Understanding Input Methods

Method Description
read *, variables List-directed input (flexible, space/comma separated)
read '(format)', variables Formatted input (strict format matching)
read(*,*) variables Equivalent to read *,
Important: When reading strings after numeric input, you may need to handle leftover newlines. List-directed input (read *,) is more forgiving and handles most common cases.

Reading Multiple Values

program multi_input
    implicit none
    integer :: x, y, z
    real :: a, b
    
    print *, "Enter three integers (space-separated): "
    read *, x, y, z
    
    print *, "Enter two real numbers: "
    read *, a, b
    
    print '(A, 3I5)', "Integers: ", x, y, z
    print '(A, 2F8.2)', "Reals: ", a, b
end program multi_input

6️⃣ Assignment Statements and Operators

Basic Assignment

The assignment operator = stores a value in a variable:

integer :: x = 10    ! declare and initialize
x = 20               ! assign new value
integer :: y = x     ! copy value from x to y

Arithmetic Operators

Operator Description Example Result (if a=10, b=3)
+ Addition a + b 13
- Subtraction a - b 7
* Multiplication a * b 30
/ Division a / b 3 (integer division)
** Exponentiation a ** b 1000
Note: Fortran uses ** for exponentiation, unlike many other languages that use ^ or pow().

Integer vs. Floating-Point Division

program division_demo
    implicit none
    integer :: a, b
    real :: r
    
    a = 7
    b = 2
    
    print *, 7 / 2          ! prints 3 (integer division)
    print *, 7.0 / 2        ! prints 3.5 (floating-point)
    print *, 7 / 2.0        ! prints 3.5 (floating-point)
    print *, a / b          ! prints 3
    print *, real(a) / b    ! prints 3.5 (explicit conversion)
    
    ! Exponentiation
    print *, 2 ** 10        ! prints 1024
    print *, 2.0 ** 0.5     ! prints 1.414... (square root)
end program division_demo
To force floating-point division with integer variables, convert one operand using real().

No Compound Assignment Operators

Unlike C-based languages, Fortran does not have compound assignment operators (+=, -=, etc.) or increment/decrement operators (++, --). You must write out the full expression:

program no_compound
    implicit none
    integer :: x = 10
    
    x = x + 5    ! No x += 5 in Fortran
    x = x - 3    ! No x -= 3
    x = x * 2    ! No x *= 2
    x = x / 4    ! No x /= 4
    
    x = x + 1    ! No x++ or ++x
    x = x - 1    ! No x-- or --x
    
    print *, x
end program no_compound

7️⃣ Control Structures

The if Statement

Execute code conditionally based on a logical expression:

program grade_calculator
    implicit none
    integer :: score
    
    print *, "Enter your score (0-100): "
    read *, score
    
    if (score >= 90) then
        print *, "Grade: A"
    else if (score >= 80) then
        print *, "Grade: B"
    else if (score >= 70) then
        print *, "Grade: C"
    else if (score >= 60) then
        print *, "Grade: D"
    else
        print *, "Grade: F"
    end if
end program grade_calculator

Comparison Operators

Operator Alternative Meaning
== .eq. Equal to
/= .ne. Not equal to
< .lt. Less than
> .gt. Greater than
<= .le. Less than or equal to
>= .ge. Greater than or equal to
Note: The symbolic operators (==, /=, <, etc.) are preferred in modern Fortran, but the older .eq., .ne., .lt. forms are still valid.

Logical Operators

Operator Meaning Example
.and. Logical AND x > 0 .and. x < 100
.or. Logical OR x < 0 .or. x > 100
.not. Logical NOT .not. found
.eqv. Logical equivalence a .eqv. b
.neqv. Logical non-equivalence a .neqv. b
program driving_check
    implicit none
    integer :: age
    character(len=3) :: response
    logical :: has_license
    
    print *, "Enter your age: "
    read *, age
    
    print *, "Do you have a license? (yes/no): "
    read '(A)', response
    
    has_license = (response == "yes")
    
    if (age >= 16 .and. has_license) then
        print *, "You can drive."
    else if (age >= 16 .and. .not. has_license) then
        print *, "You're old enough but need a license."
    else
        print *, "You're too young to drive."
    end if
end program driving_check

The select case Statement

Use select case when comparing a single value against multiple options:

program day_of_week
    implicit none
    integer :: day
    
    print *, "Enter a day number (1-7): "
    read *, day
    
    select case (day)
        case (1)
            print *, "Monday"
        case (2)
            print *, "Tuesday"
        case (3)
            print *, "Wednesday"
        case (4)
            print *, "Thursday"
        case (5)
            print *, "Friday"
        case (6, 7)  ! Multiple values in one case
            print *, "Weekend!"
        case default
            print *, "Invalid day number"
    end select
end program day_of_week
Fortran Feature: The select case statement does not require break statements—each case automatically ends without falling through to the next.

Case Ranges

Fortran allows ranges in case statements:

select case (score)
    case (90:100)
        print *, "Grade: A"
    case (80:89)
        print *, "Grade: B"
    case (70:79)
        print *, "Grade: C"
    case (:69)  ! 69 and below
        print *, "Below C"
    case default
        print *, "Invalid score"
end select

8️⃣ Looping Structures

The do Loop (Counted Loop)

Best for iterating a specific number of times:

program do_loop_demo
    implicit none
    integer :: i
    
    ! Basic counting (1 to 5)
    do i = 1, 5
        print *, "Iteration ", i
    end do
    
    ! Counting down
    print *, ""
    print *, "Countdown:"
    do i = 10, 0, -1
        print *, i
    end do
    
    ! Step by 2
    print *, ""
    print *, "Even numbers:"
    do i = 2, 10, 2
        print *, i
    end do
end program do_loop_demo

Syntax: do variable = start, end [, step]

The do while Loop

Repeats as long as a condition is true:

program while_demo
    implicit none
    integer :: i
    
    ! Count from 1 to 5
    i = 1
    do while (i <= 5)
        print *, "Count: ", i
        i = i + 1
    end do
end program while_demo

Infinite Loop with exit

Use do without bounds and exit to create flexible loops:

program guessing_game
    implicit none
    integer :: guess
    integer :: secret_number = 7
    
    do
        print *, "Guess a number (1-10): "
        read *, guess
        
        if (guess < secret_number) then
            print *, "Too low!"
        else if (guess > secret_number) then
            print *, "Too high!"
        else
            print *, "Correct!"
            exit  ! Exit the loop
        end if
    end do
end program guessing_game

Loop Control: exit and cycle

Statement Description
exit Immediately exit the loop
cycle Skip to the next iteration
program loop_control
    implicit none
    integer :: i
    
    ! exit - find first multiple of 7
    print *, "Finding first multiple of 7:"
    do i = 1, 100
        if (mod(i, 7) == 0) then
            print *, "Found: ", i
            exit
        end if
    end do
    
    ! cycle - skip multiples of 3
    print *, ""
    print *, "Numbers 1-10, skipping multiples of 3:"
    do i = 1, 10
        if (mod(i, 3) == 0) then
            cycle
        end if
        print *, i
    end do
end program loop_control

Named Loops

Fortran allows you to name loops, which is useful for nested loops:

program named_loops
    implicit none
    integer :: i, j
    
    outer: do i = 1, 5
        inner: do j = 1, 5
            if (i * j > 10) then
                exit outer  ! Exit the outer loop
            end if
            print '(I2, A, I2, A, I3)', i, " x ", j, " = ", i*j
        end do inner
    end do outer
end program named_loops

Nested Loops

program multiplication_table
    implicit none
    integer :: row, col
    
    print *, "Multiplication Table (1-5):"
    print *, ""
    
    ! Print header row
    write(*,'(A)', advance='no') "    "
    do col = 1, 5
        write(*,'(I4)', advance='no') col
    end do
    print *, ""
    print *, "   --------------------"
    
    ! Print table rows
    do row = 1, 5
        write(*,'(I2, A)', advance='no') row, " |"
        do col = 1, 5
            write(*,'(I4)', advance='no') row * col
        end do
        print *, ""
    end do
end program multiplication_table
Note: Use advance='no' to prevent a newline after a write statement.

9️⃣ Complete Example: Temperature Converter

This program demonstrates input, output, control structures, and loops working together:

program temperature_converter
    implicit none
    integer :: choice
    real :: celsius, fahrenheit
    logical :: running
    
    print *, "=== Temperature Converter ==="
    print *, "1. Celsius to Fahrenheit"
    print *, "2. Fahrenheit to Celsius"
    print *, "3. Quit"
    
    running = .true.
    
    do while (running)
        print *, ""
        print *, "Enter choice (1-3): "
        read *, choice
        
        select case (choice)
            case (1)
                print *, "Enter temperature in Celsius: "
                read *, celsius
                fahrenheit = (celsius * 9.0 / 5.0) + 32.0
                print '(F8.2, A, F8.2, A)', celsius, "°C = ", fahrenheit, "°F"
                
            case (2)
                print *, "Enter temperature in Fahrenheit: "
                read *, fahrenheit
                celsius = (fahrenheit - 32.0) * 5.0 / 9.0
                print '(F8.2, A, F8.2, A)', fahrenheit, "°F = ", celsius, "°C"
                
            case (3)
                print *, "Goodbye!"
                running = .false.
                
            case default
                print *, "Invalid choice. Please enter 1, 2, or 3."
        end select
    end do
end program temperature_converter

🔟 Quick Reference

Task Fortran Syntax
Print with newline print *, "text", variable
Formatted print print '(A, I5)', "Value: ", x
Read with list-directed input read *, variable
Read string read '(A)', string_var
Compile gfortran filename.f90 -o outputname
Run ./outputname
Disable implicit typing implicit none
Declare integer integer :: n
Declare real real :: x
Declare double precision double precision :: d
Declare string character(len=20) :: s
Declare constant real, parameter :: PI = 3.14159
Convert to real real(int_var)
Convert to integer int(real_var)
Modulus mod(a, b)

📝 Programming Exercise: Prime Number Analyzer

Write a Fortran program that analyzes prime numbers. Your program should:

  1. Prompt the user to enter a positive integer n (must be ≥ 2)
  2. Validate the input: If the user enters a number less than 2, display an error message and ask again (use a loop)
  3. Determine if n is prime: A prime number is only divisible by 1 and itself
  4. If n is prime: Display "n is a prime number!"
  5. If n is not prime: Display "n is not prime. Its smallest factor is f." (where f is the smallest factor other than 1)
  6. Count and display how many prime numbers exist from 2 up to and including n
  7. Ask the user if they want to check another number (y/n). If yes, repeat; if no, exit with a goodbye message

Sample Output

=== Prime Number Analyzer === Enter a positive integer (>= 2): 1 Invalid input. Please enter a number >= 2. Enter a positive integer (>= 2): 29 29 is a prime number! There are 10 prime numbers from 2 to 29. Check another number? (y/n): y Enter a positive integer (>= 2): 100 100 is not prime. Its smallest factor is 2. There are 25 prime numbers from 2 to 100. Check another number? (y/n): n Goodbye!

Hints

Submission

Save your program as prime_analyzer.f90 and compile with:

gfortran prime_analyzer.f90 -o prime_analyzer
./prime_analyzer