Section Computing Pi: Compute Pi#

Adapted from: gjbex/Fortran-MOOC

This program demonstrates computing \(\pi\) in Fortran by using the following equation:#

\[ \Large \pi = 4 \int_{0}^{1} \sqrt{1-x^2}dx \]

In file section_computing_pi_compute_pi.f90#

program compute_pi
    use, intrinsic :: iso_fortran_env, only : DP => REAL64, I8 => INT64
    implicit none
    integer(kind=I8) :: i, nr_iters
    real(kind=DP) :: delta, x, pi_val
    real(kind=DP) :: pi_val_actual

    pi_val = 0.0_DP
    pi_val_actual = 2.0_DP * acos(0.0_DP)
    nr_iters = get_nr_iters()
    delta = 1.0_DP/nr_iters
    x = 0.0_DP
    do i = 1, nr_iters
        pi_val = pi_val + sqrt(1.0_DP - x**2)
        x = x + delta
    end do
    pi_val = 4.0_DP*pi_val/nr_iters
    print '(A, I10, A, F25.15)', "After ", nr_iters, " loops, Pi = ", pi_val
    print '(A, F25.15)', "Actual value of Pi = ", pi_val_actual
    print '(A, F25.15)', "Absolute difference = ", abs(pi_val - pi_val_actual)

contains
     
    function get_nr_iters() result(nr_iters)
        use, intrinsic :: iso_fortran_env, only : error_unit
        implicit none
        integer(kind=I8) :: nr_iters
        integer(kind=I8), parameter :: default_nr_iters = 1000_I8
        character(len=1024) :: buffer, msg
        integer :: istat

        if (command_argument_count() >= 1) then
            call get_command_argument(1, buffer)
            read (buffer, fmt=*, iostat=istat, iomsg=msg) nr_iters
            if (istat /= 0) then
                write (unit=error_unit, fmt='(2A)') &
                    'error: ', msg
                stop 1
            end if
        else
            nr_iters = default_nr_iters
        end if
    end function get_nr_iters

end program compute_pi

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()

The following configuration file (fpm.toml) was used:

name = "Section_Computing_Pi_Compute_Pi"

[build]
auto-executables = true
auto-tests = true
auto-examples = true

[install]
library = false

[[executable]]
name="Section_Computing_Pi_Compute_Pi"
source-dir="app"
main="section_computing_pi_compute_pi.f90"
code_dir = root_dir + "/" + "Fortran_Code/Section_Computing_Pi_Compute_Pi"
os.chdir(code_dir)
build_status = os.system("fpm build 2>/dev/null")

Run the Program using FPM (Fortran Package Manager)#

10 Iterations#

%%timeit -r 10 -n 1
exec_status = os.system("fpm run -- 10 2>/dev/null > output.txt")
43.7 ms ± 4.15 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)
%cat output.txt
After         10 loops, Pi =         3.304518326248318
Actual value of Pi =         3.141592653589793
Absolute difference =         0.162925672658525

100 Iterations#

%%timeit -r 10 -n 1
exec_status = os.system("fpm run -- 100 2>/dev/null > output.txt")
42.2 ms ± 5.83 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)
%cat output.txt
After        100 loops, Pi =         3.160417031779042
Actual value of Pi =         3.141592653589793
Absolute difference =         0.018824378189249

1,000 Iterations#

%%timeit -r 10 -n 1
exec_status = os.system("fpm run -- 1000 2>/dev/null > output.txt")
45.3 ms ± 4.54 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)
%cat output.txt
After       1000 loops, Pi =         3.143555466911022
Actual value of Pi =         3.141592653589793
Absolute difference =         0.001962813321229

10,000 Iterations#

%%timeit -r 10 -n 1
exec_status = os.system("fpm run -- 10000 2>/dev/null > output.txt")
51.2 ms ± 21.8 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)
%cat output.txt
After      10000 loops, Pi =         3.141791477611602
Actual value of Pi =         3.141592653589793
Absolute difference =         0.000198824021809

100,000 Iterations#

%%timeit -r 10 -n 1
exec_status = os.system("fpm run -- 100000 2>/dev/null > output.txt")
The slowest run took 4.78 times longer than the fastest. This could mean that an intermediate result is being cached.
66.7 ms ± 48.1 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)
%cat output.txt
After     100000 loops, Pi =         3.141612616406209
Actual value of Pi =         3.141592653589793
Absolute difference =         0.000019962816416

1,000,000 Iterations#

%%timeit -r 10 -n 1
exec_status = os.system("fpm run -- 1000000 2>/dev/null > output.txt")
51.1 ms ± 14.8 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)
%cat output.txt
After    1000000 loops, Pi =         3.141594652402481
Actual value of Pi =         3.141592653589793
Absolute difference =         0.000001998812688

10,000,000 Iterations#

%%timeit -r 10 -n 1
exec_status = os.system("fpm run -- 10000000 2>/dev/null > output.txt")
68.9 ms ± 11.1 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)
%cat output.txt
After   10000000 loops, Pi =         3.141592854147901
Actual value of Pi =         3.141592653589793
Absolute difference =         0.000000200558108

100,000,000 Iterations#

%%timeit -r 10 -n 1
exec_status = os.system("fpm run -- 100000000 2>/dev/null > output.txt")
304 ms ± 16 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)
%cat output.txt
After  100000000 loops, Pi =         3.141592668260093
Actual value of Pi =         3.141592653589793
Absolute difference =         0.000000014670300

1,000,000,000 Iterations#

%%timeit -r 10 -n 1
exec_status = os.system("fpm run -- 1000000000 2>/dev/null > output.txt")
2.64 s ± 135 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)
%cat output.txt
After 1000000000 loops, Pi =         3.141592665675041
Actual value of Pi =         3.141592653589793
Absolute difference =         0.000000012085248