Section: Implicit vs. Explicit Loops#

Adapted from: gjbex/Fortran-MOOC

This program demonstrates the speed of implicit vs. explicit loops in Fortran.#

The program will take in a command line argument and construct two argument X argument sized matrices composed of random numbers. The program will then compute the following:

\[ \Large Result = \sum \sqrt{X^2 + Y^2} \]

where:
\(Result\) is the summation result
\(X\) and \(Y\) are command line argument X command line argument sized matrices

program real32_vs_real64
    use, intrinsic :: iso_fortran_env, only : error_unit, I8 => INT64, &
        SP => REAL32, DP => REAL64
    implicit none
    integer(kind=I8) :: nr_values
    real(kind=SP), dimension(:), allocatable :: x_sp, y_sp
    real(kind=SP) :: result
    real :: start_time, end_time
    integer :: status, i

    call get_argument(nr_values)

    ! implicit loops
    allocate (x_sp(nr_values), y_sp(nr_values), stat=status)
    if (status /= 0) then
        write (unit=error_unit, fmt='(A)') 'error: can not allocate x_sp/y_sp'
        stop 1
    end if
    call random_number(x_sp)
    call random_number(y_sp)

    call cpu_time(start_time)
    result = sum(sqrt(x_sp**2 + y_sp**2))
    call cpu_time(end_time)
    print '(A, F20.8)', 'Implicit loop time [s]: ', end_time - start_time
    print '(A, F20.8)', 'Summation result: ', result
    deallocate (x_sp, y_sp)

    ! explicit loops
    allocate (x_sp(nr_values), y_sp(nr_values), stat=status)
    if (status /= 0) then
        write (unit=error_unit, fmt='(A)') 'error: can not allocate x_sp/y_sp'
        stop 1
    end if
    call random_number(x_sp)
    call random_number(y_sp)

    call cpu_time(start_time)
    result = 0.0_SP
    do i = 1, size(x_sp)
        result = result + sqrt(x_sp(i)**2 + y_sp(i)**2)
    end do
    call cpu_time(end_time)
    print '(A, F20.8)', 'Explicit loop time [s]: ', end_time - start_time
    print '(A, F20.8)', 'Summation result: ', result
    deallocate (x_sp, y_sp)

contains

    subroutine get_argument(nr_values)
        implicit none
        integer(Kind=I8), intent(out) :: nr_values
        character(len=1024) :: buffer, msg
        integer :: status

        if (command_argument_count() /= 1) then
            write (unit=error_unit, fmt='(A)') 'error: expect number of values'
            stop 2
        end if
        call get_command_argument(1, buffer)
        read (buffer, fmt=*, iomsg=msg, iostat=status) nr_values
        if (status /= 0) then
            write (unit=error_unit, fmt='(2A)') 'error: ', trim(msg)
            stop 3
        end if
    end subroutine get_argument

end program real32_vs_real64

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

Build the Program using FPM (Fortran Package Manager)#

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

Run the Program using FPM (Fortran Package Manager)#

exec_status = os.system("fpm run -- 10 2>/dev/null")
Implicit loop time [s]:           0.00000100
Summation result:           7.26918840
Explicit loop time [s]:           0.00000100
Summation result:           8.26918221
exec_status = os.system("fpm run -- 100 2>/dev/null")
Implicit loop time [s]:           0.00000100
Summation result:          78.46569824
Explicit loop time [s]:           0.00000100
Summation result:          73.05465698
exec_status = os.system("fpm run -- 1000 2>/dev/null")
Implicit loop time [s]:           0.00000300
Summation result:         761.32910156
Explicit loop time [s]:           0.00000200
Summation result:         770.70007324
exec_status = os.system("fpm run -- 10000 2>/dev/null")
Implicit loop time [s]:           0.00001000
Summation result:        7655.58251953
Explicit loop time [s]:           0.00002200
Summation result:        7623.15283203
exec_status = os.system("fpm run -- 100000 2>/dev/null")
Implicit loop time [s]:           0.00010700
Summation result:       76680.54687500
Explicit loop time [s]:           0.00022600
Summation result:       76532.14062500
exec_status = os.system("fpm run -- 1000000 2>/dev/null")
Implicit loop time [s]:           0.00130100
Summation result:      764747.62500000
Explicit loop time [s]:           0.00223100
Summation result:      765129.37500000
exec_status = os.system("fpm run -- 10000000 2>/dev/null")
Implicit loop time [s]:           0.01117000
Summation result:     7670801.00000000
Explicit loop time [s]:           0.02379100
Summation result:     7670755.50000000
exec_status = os.system("fpm run -- 100000000 2>/dev/null")
Implicit loop time [s]:           0.13284096
Summation result:    33554432.00000000
Explicit loop time [s]:           0.27633798
Summation result:    33554432.00000000