Types and Kinds#

INTRO HERE?

Types#

There are five types in Fortran. They are:

Type

example

integer

1

real (float)

1.0 or 1.2d-11

character

'text'

complex

( 1.0, 1.0 )

logical

.true. or .false

Declaring Variables#

Variables can be declared using the :: syntax:

integer :: i, j        ! simple counters for looping
real    :: my_height

Here we declared two integer variables, then a real variable. Notice how the :: are aligned for readability. Variables names can contain letters, numbers, and _ only. They must start with a letter.

implicit none#

Fortran assumes that the single character variables i through n will be used for counting during loops and automatically declares them as integer types. It is good practice in modern Fortran to declare implicit none at the start of all programs, modules, functions, and subroutines to supress this behaviour.

Assigning Variables#

Variables can be assigned when they are declared however it is best practice to assign a value with a new statement for instance:

integer :: i, j        ! simple counters for looping
real    :: my_height

i         = 0
my-height = 54.7

Note

Always ensure variables are assinged a value. If a variable is delcared and referenced but not assigned unexpected behaviour can occur:

real :: y
print *, y
! gfortran prints 4.56472975E-41
! ifort prints 0

Here the gfortran compiler printed what was already in the memory it assigned for y, whereas the ifort compiler set the value to zero.

Parameters#

Parameters are variables with a fixed value that cannot be changed. Parameters must be declared with their value:

real                    :: earth_radius = 6371000
character(*), parameter :: earth_radius_unit = 'm'

They are often used, as in the example above, for physical constants.

Tip

Fortran doesn’t have any built in constants such as \(e\) or \(\pi\). To calculate these constants use:

e  = exp(1.0)
pi = 4.0*atan(1.0)

From Rosetta Code.

Character Type#

Characters are declared with a length variable. This allocates the correct amount of memory for the string length. If the string is shorter than the declared length it will be padded with spaces. If the string is longer than the declared length it will be cut to the declared length.

Interactive

Make sure you have [activated interactivity]() on this page.

  • Run the code as is, what does it do?
  • Change the assigned string 'Voyager' to 'Enterprise', what happens to the stored string?
  • Keeping the 'Enterprise' string change the len=7 command to `len=*` or simply to `*` and make the variable space_ship a parameter, what happens to the stored string?
character(len=7) :: space_ship = 'Voyager'
print *, space_ship

data Statements#

In some older code you may come across the data statement. This statement causes the compiler to load some initial values into variables at compile time; it is a nonexecutable statement. It takes the general form:

data varlist /vallist/ [, varlist /vallist/]

For example:

data a,b,c / 1.,2.,3./
data a,b,c / 1.,2.,3. /, X,Y,Z / 4.,5.,6. /
data ra / 100*1.0 /

Note

Objects initialised by the data statement have the save attribute. 2
It is recommended NOT to use the data statement in most cases in favour of the type delcaration statement !!! ref to sec. 3

Kinds#

The default precision for real numbers in Fortran is single precision (sp). You should take care when declaring any number to specify a kind (precision).

To declare the precision of a number using kind:

 ! hardware specific 32 bit real (sp)
integer, parameter :: r_32 = selected_real_kind(6, 37)
! hardware specific 64 bit real
integer, parameter :: r_64 = selected_real_kind(15, 307)

! kind can be ommitted but this is not recommended
real(r_32)      :: height
real(kind=r_64) :: earth_radius = 6371229.0_r_64

Here we defined our precisions as integer parameters to initialise our real numbers with. The real variable height is single precision whereas the real variable earth_radius is double precision (dp). Notice that we also assigned a number to eath_radius when we delcared it. This number ends in _r_64 denoting it is a double precision real number. Without this Fortran will assign the number as single not double precision.

There are other ways to declare the precision of a variable, you may see: 3.14d0 instead of 3.14_r_64 to denote double precision. You may also see kinds declared in byte units: REAL*8, this does not conform to the Fortran standard and should not be used.

Where possible avoid using d and follow the example above to declare a variables kind.You may also see use of the intrinsic Fortran module iso_fortran_env. Kinds are declared with this module as below:

! module use statement
use, intrinsic :: iso_fortran_env, only: int64, real64, real128

integer, parameter :: i_64  = int64
integer, parameter :: r_64  = real64
integer, parameter :: r_128 = real128

real(kind=r_64)    :: x = 1.0_r_64
real(kind=r_64)    :: y
y = 1.0       ! single precision
y = 1.0_r_64  ! double precision

In this snippet three kinds: a 64 bit integer, a 64 bit real, and a 128 bit real, were loaded. Again note the warning about assingning a double precision value to a declared variable. The use of intrinisc modules and how to create your own is dealt with in the !!! section.

Note

For character types the kind must precede the string and the kind relates to the character set used. This will not be explored further in this course.

integer, parameter         :: ck = kind('A')
character(kind=ck, len=12) :: title

title = ck_'The Good Place'

Precision Tips#

This list may seem long but as you write more Fortran code they will become part of your standard practice.

  • DO ensure all real values have the correct kind declared

  • DO assign high precision constants

  • DO assign dp variables with a kind such as r_64, eg. 3.14_r_64

  • DO use a module to store your kind declarations, see good practice in constants_mod.f90

  • Avoid using compiler flags to set default precision, set explicitly using kinds

  • Avoid mixing types in arithmetic

  • Avoid converting from high to lower precision types

Converting Types & Kinds#

Converting between kinds is possible:

real(x, sp) ! converts to the kind sp (single precision)
real(x, dp) ! converts to the kind dp (double precision)

Tip

Use the intrinsic function nint(x) to convert a real number to the nearest integer.

Conversion between other types and kinds is dealt with in the Internal IO section.

Overflow and Underflow#

If a number becomes so large it cannot be represented anymore by your chosen kind then you have overflow and vice versa for underflow. To see the largest and smallest numbers a kind can represent use the functions:

epsilon(x) ! 1.19209290E-07, effectively negligible number for x's kind
huge(x)    ! 3.40282347E+38, largest number
tiny(x)    ! 1.17549435E-38, smallest number

Here x is a double precision real and the example output, printed using print *, tiny(x) for instance, is for a typical 64 bit linux machine. To test for overflow huge(x) can be used:

if ( real1 <= huge(real1) ) then
    ...
else
    error stop 'Overflow'
end if

To deal with underflow use tiny(x):

if ( abs(real1 - real2) < tiny(real1) ) then
    ...
end if

Summary#

Exercises#

Exercise 2

Write a program that declares and initialises these variables:

  • Two integers

  • A single precision real

  • A double precision real

  • A parameter containing the value of \(\pi\)

  • A complex number

  • Two character strings

Be sure to use correct style (program name, no implicit typing, correct declarations). You will be able to use snippets from this program to help you with the next set of exercises.


1

The length can also be automatically calculated on allocation character(len=:), allocatable :: c, see memory management for information on allocatables.

2

Data save attribute reference, Adam Marshall.

3

page 140 of Modern Fortran Explained (the green edition from 2011 !!! ADD PROPER REF