Basic Fortran
Basic Fortran
Fortran is a compiled language where you write the program in one or more source files that are compiled into objects that are linked together to produce an executable.
program, implicit none, real, print
! A very simple example
program ex1
implicit none
real(kind=8) :: a,b,c
a = 1.d0
b = exp(a)
c = a+b
print *, "The output is = ", c
end program ex1
$ gfortran -c ex1.f90
$ gfortran -o ex1.x ex1.o
$ ./ex1.x
The output is = 3.7182818284590451
FORTRAN stands for FOR mula TRAN slator and came to use with then first version Fortran I in 1954. Versions II, III, IV and Fortran 66 are all but forgotten but the more modern Fortran 77 is still very much in use.
The version we will use is a mix of Fortran 90/95/2003. Mainly we will use features that were introduced already in F90 but we will also need some features from 95/2003. Many of the features in the more modern Fortran standards make the language look more like C / C++ but we won’t touch on these at all.
Unlike e.g. perl Fortran is case insensitive.
In Fortran 77 there are some quirky rules for the syntax. For example each line may have a fixed length (typically 72 characters) and has to start with 6 blanks. This is requirements carried over from the days of punch cards.
In modern Fortran each line can contain 132 characters but every line can be continued by & (up to 39 times in F95 and more in F2003).
Intrinsic Data Types:
An integer is simply…. an integer like 1, 2, 0, -2, 1234.
The range of an integer is not specified in the language but typically it is \(-2^{n-1}\) to \(+2^{n-1} -1\) with \(n\) being the word size in bits. So on a 32-bit computer the range would be -2147483648 to 2147483647.
Fortran allows for you to select the range by
integer, parameter :: k3 = selected_int_kind(3)
integer (kind = k3) :: i,j,k
! integer (k3) :: i,j,k ! Alternative form
! i,j,k are in the range -999,999
i = 22_k3 ! Makes sure 22 is of kind k3
selected_real_kind(D,E)
where D
is number of digits and
E
is the exponent.DOUBLE PRECISION
which is not strictly
set in standard, although in practice it is often the same as selected_real_kind(15, 307)
integer, parameter :: dp = selected_real_kind(15, 307) ! Or integer, parameter :: dp = kind(1.d0) ! Or all of single, double and quad integer, parameter :: & sp = kind(1.0), & dp = selected_real_kind(2*precision(1.0_sp)), & qp = selected_real_kind(2*precision(1.0_dp)) ! Or by the F2008 iso standard use, intrinsic :: iso_fortran_env integer, parameter :: sp = REAL32 integer, parameter :: dp = REAL64 ! If you are planning to mix and match with C use iso_c_binding integer, parameter:: sp = c_float integer, parameter:: dp = c_double integer, parameter:: li = c_long real(kind = dp) :: x,y,z integer(kind = li) :: ii,jj,kk
program apa1 use, intrinsic :: iso_fortran_env implicit none real(REAL64), parameter :: pi_1 = 3.141592653589793238462643383279502884197169_REAL64 real(REAL64), parameter :: pi_2 = 3.141592653589793238462643383279502884197169 write(*,*) pi_1-acos(-1.d0), pi_1-acos(-1.0) write(*,*) pi_2-acos(-1.d0), pi_2-acos(-1.0) write(*,*) pi_1, pi_2 end program apa1$ gfortran apa1.f90 $ ./a.out 0.0000000000000000 -8.7422780126189537E-008 8.7422780126189537E-008 0.0000000000000000 3.1415926535897931 3.1415927410125732
The different numerical types can be scalars or arrays.
Arrays are very flexible in Fortran and can have 7 dimensions (rank) or 15 for those compilers (Intel but not gfortran) that support it (F2008 standard).
Some examples:
real, dimension(-1:3) :: a
real(-2:2) :: b
real, dimension(3,0:2) :: c
integer, parameter :: n = 10
integer, dimension(n,n,n,n) :: i4
Accessing elements in an array
a(-1:3:2) = 1.0
b(:) = a(:)
Explicit-shape arrays in the beginning of the main program are allocated at compile/run time.
Deferred-shape arrays can be allocatable
or pointers
real, allocatable, dimension(:,:) :: a
allocate(a(10,0:33))
! Stuff ...
deallocate(a)
We will talk more about arrays once we discuss subroutines.
The if else
statement:
if (i .ge. 3) p = 1.0 if (i .ge. 3) then p = 1.0 end ifif (i .ge. 3) then p = 1.0 else if (i .eq. 1) then p = 2.0 else p = 1.0 end ifname: if (i >= 3) then p = 1.0 end if name
n = 10 sum = 0.0 do i = 1,n,3 sum = sum + 1.0 end dodo i = j+4,m,-k(j)**2 sum = sum + 1.0 end doi = 1 do i = i*(i+1) if (i .le. 10) exit end do
Preferred
do j = 1,10 do i = 1,10 a(i,j) = 1.0 end do end do
Slower
do i = 1,10 do j = 1,10 a(i,j) = 1.0 end do end do
select case (number) ! numer is an integer case (:-1) ! all values below 0 sgn = -1 case (0) ! only 0 sgn = 0 case (1:) ! all values above 0 sgn = 1 end select
integer, parameter :: n = 3
real(kind = dp), parameter :: pi = 3.141592653589793238462643383279_dp
integer :: i
real(kind = dp) :: a
real :: c = 0.0
logical :: correct
do i = 1,n
if ( i < 2) then
c = c + pi ; a = abs(dble(i)*pi-c)/(dble(i)*pi) ; correct = .false.
elseif (i == 2) then
a = (i/n)*pi ; correct = .false.
else
a = (i/n)*pi ; correct = .true.
endif
print *, i, a, correct
end do
Be careful with single/double precision!
real(kind = dp) :: a
real :: c = 0.0
logical :: correct
do i = 1,n
if ( i < 2) then
c = c + pi ; a = abs(dble(i)*pi-c)/(dble(i)*pi) ; correct = .false.
elseif (i == 2) then
a = (i/n)*pi ; correct = .false.
else
a = (i/n)*pi ; correct = .true.
endif
print *, i, a, correct
end do
1 2.7827535191837951E-008 F
2 0.0000000000000000 F
3 3.1415926535897931 T
program pfun
implicit none
real(dp) :: x,y
real(dp), external :: myfun
x = 3.d0
y = myfun(x)
write(*,*) "x = ",x, "and y = ",y
end program pfun
real(dp) function myfun(x)
real(dp), intent(in) :: x
myfun = x*x
end function myfun
External functions must be declared as external
. Use intent to
help the compiler. Write
instead of print
. The function is
external although it is in the same file as the program. It is outside
the program statement.
This function is pure, it does not have any side effects.
program psub
implicit none
real(dp) :: x,y
x = 3.0_dp
call mysub(x,y)
write(*,*) "x = ",x, "and y = ",y
end program psub
subroutine mysub(x,y)
implicit none
real(dp), intent(in) :: x
real(dp), intent(out) :: y
y = x*x
end subroutine mysub
Subroutines does not return anything and does not have to be declared.
BE CAREFUL WITH ARGUMENTS!!! They are typically NOT checked
program psub_bugs
implicit none
real(dp) :: x,y
real(sp) :: s
integer :: k
x = 3.0_dp ; s = 3.0_sp ; k = 3
call mysub(x,y) ; write(*,*) "x = ",x, "and y = ",y
call mysub(s,y) ; write(*,*) "x = ",s, "and y = ",y
call mysub(k,y) ; write(*,*) "x = ",k, "and y = ",y
end program psub_bugs
$ gfortran psub_bugs.f90; ./a.out
x = 3.0000000000000000 and y = 9.0000000000000000
x = 3.00000000 and y = 0.0000000000000000
x = 3 and y = Infinity
There are three program units in Fortran
PROGRAM
MODULE
SUBROUTINE
/ FUNCTION