Basics of Fortran

Note This chapter of the lecture note has been partially extracted and modified from Prof. LeVeque’s (Univ. of Washington) online note on Fortran. Some parts of the chapter also has been adopted and modified from Prof. Garaud’s (AM, UCSC) short notes on Fortran:

History

FORTRAN stands for FORmula TRANslator and was the first major high level language to catch on. The first compiler was written in 1954-57. Before this, programmers generally had to write programs in a low-level programming language called assembly.

Many version followed: Fortran II, III, IV. Fortran 66 followed a set of standards formulated in 1966.

See also

for brief histories.

Fortran 77

The standards established in 1977 lead to Fortran 77, or f77, and some codes are still in use that follow this standard. Fortran 77 does not have all the features of newer versions and many things are done quite differently.

One feature of f77 is that lines of code have a very rigid structure. This was required in early versions of Fortran due to the fact that computer programs were written on punched cards. All statements must start in column 7 or beyond and no statement may extend beyond column 72. The first 6 columns are used for things like labels (numbers associated with particular statements). In f77 any line that starts with a ‘c’ in column 1 is a comment.

We will not use f77 in this class, but if you need to work with Fortran in the future you may need to learn more about it because of all the legacy codes that still use it (see also f77-wikibooks).

Fortran 90/95

Dramatically new standards were introduced with Fortran 90, and these were improved in mostly minor ways in Fortran 95. There are newer Fortran 2003 and 2008 standards. GCC, Intel, and PGI, (almost) fully support the Fortran 2003 and 2008 standards. An even newer standard is Fortran 2018, though there are still a few items in the standard that are up for debate. See the GFortran manual for more information on the support of the various standards in gfortran.

For this class we will focus on features of the language following the the Fortran 90 standard. Everything that we write will be automatically be applicable to later versions of the language. However, some of the nice features from the newer standards will be mentioned as we go along. You are welcome to use these in your assignments and projects.

A few helpful resources for Fortran are:

Why Fortran?

Frequently, people ask what is the advantage of using Fortran as opposed to using other modern scientific languages, such as C/C++. One good explanation can be found here: FAQ. The exceedingly short answer is the same as any language preference discussion: use the language that suits the problem at hand.

Compilers

Unlike Python (which is an interpreted language), Fortran (which is a compiled language) must pass through several stages before being executed (i.e., compilation). There are several different compilers that can turn Fortran code into an executable (or binary), as described below.

In this class we will use gfortran, which is an open source compiler, part of the GNU Project, and ships as part of the GNU Compiler Collection (GCC). See http://gcc.gnu.org/fortran/ for more about gfortran.

There are several commercial compilers which are better in some ways, in particular they sometimes do better optimization and produce faster running executables. They also may have better debugging tools built in. Some popular ones are the Intel and Portland Group compilers.

Getting gfortran

The process for getting gfortran on your machine depends on whether you are using MacOS or Linux, and on which distribution of Linux you have. Before going any further you should check if you already have it installed. Try running the following commands:

$ which gfortran
$ gfortran --version

If those succeed then you already have gfortran and you can skip this section. If those fail and you are on Linux, then you can install gfortran using your package manager. For Ubuntu you would run:

$ sudo apt update && sudo apt install gfortran

For Arch Linux and its derivatives you would run:

$ sudo pacman -Sy && sudo pacman -S gcc-fortran

For other Linux distributions please reference their documentation.

For MacOS you can install gfortran using the Homebrew package manager by running:

$ xcode-select --install
$ brew install gcc

File extensions

Fortran code can be compiled in a few different modes as a result of some of the constraints present in earlier versions, or to provide extended functionality. The gfortran compiler will choose some default compilation settings based on the file extension of the source file.

The most common file extensions are *.f, *.ftn, and *.f<std> where <std> is a number indicating the standard used (e.g. *.f90). There are also uppercase versions of these file extensions.

Note

In short, all of your source files in this class should use either the *.f90 or the *.F90 extension.

These file extensions influence two important settings during compilation. The first is whether a source file is processed in fixed form or free form. Files that aren’t labelled with a standard after Fortran 90 will default to fixed form, which is the highly rigid and slightly arcane form described above in Fortran 77. Free format code is much easier to read and to write, so we will prefer file extensions of the form *.f<std>.

To make matters even more confusing, most people use the *.f90 and *.F90 extensions for all Fortran from Fortran 90 onwards. In fact, some compilers don’t even recognize extensions like *.f03 by default.

The other important setting is chosen based on the case of the file extension, say *.f90 versus *.F90. Uppercase file extensions will activate an extra feature called the preprocessor. When using gfortran this will actually be the same preprocessor used for C code, and we’ll talk about it in more depth in a later chapter. To get a flavor of it, consider this sample file from the FLASH astrophysics code:

 1!!****if* source/physics/Hydro/HydroMain/unsplit/hy_uhd_avgState
 2!!
 3!! NAME
 4!!
 5!!  hy_uhd_avgState
 6!!
 7!! SYNOPSIS
 8!!
 9!!  hy_uhd_avgState( integer(IN) :: sweepDir,
10!!                   real(IN)  :: VL(HY_VARINUM3),
11!!                   real(IN)  :: VR(HY_VARINUM3),
12!!                   real(OUT) :: Vavg(HY_VARINUM2) )
13!!
14!! DESCRIPTION
15!!
16!!  This routine computes proper average state values at each interface
17!!  using a simple arithmatic average.
18!!  The calculated average state values are used in the Roe and Lax-Friedrichs
19!!  Riemann solvers.
20!!
21!! ARGUMENTS
22!!
23!!  sweepDir - sweep direction
24!!  VL    -  a vector array for the left state  
25!!            (DENS,VELX,VELY,VELZ,MAGX,MAGY,MAGZ,PRES + GAMC,GAME,EINT)
26!!  VR    -  a vector array for the right state 
27!!            (DENS,VELX,VELY,VELZ,MAGX,MAGY,MAGZ,PRES + GAMC,GAME,EINT)
28!!  Vavg  -  a vector array for the computed average state
29!!            (DENS,VELX,VELY,VELZ,MAGX,MAGY,MAGZ,PRES + GAMC,GAME)
30!!
31!!*** 
32#include "Flash.h"
33#include "UHD.h"
34
35Subroutine hy_uhd_avgState(sweepDir,VL,VR,Vavg)
36
37#if defined(FLASH_USM_MHD) || defined(FLASH_UGLM_MHD)
38  use Hydro_data,           ONLY : hy_forceHydroLimit
39#endif
40  use hy_uhd_slopeLimiters, ONLY : signum
41
42  implicit none
43
44#include "Flash.h"
45#include "UHD.h"
46!! Arguments type declaration -----------------
47  integer, intent(IN) :: sweepDir
48  real, dimension(HY_VARINUM3), intent(IN)  :: VL,VR
49  real, dimension(HY_VARINUM2), intent(OUT) :: Vavg
50!! --------------------------------------------
51  real :: sig
52
53!! Arithmetic averages
54  Vavg(HY_DENS:HY_GAME) = .5*(VL(HY_DENS:HY_GAME)+VR(HY_DENS:HY_GAME))
55
56#if defined(FLASH_USM_MHD) || defined(FLASH_UGLM_MHD)
57  if (hy_forceHydroLimit) Vavg(HY_MAGX:HY_MAGZ) = 0.
58#endif
59
60!! Use upwinding for game and gamc that are averaged along the
61!! entropy wave.
62  sig = signum(Vavg(sweepDir+1))
63  Vavg(HY_GAMC:HY_GAME) = 0.5*( (1.+sig)*VL(HY_GAMC:HY_GAME) &
64      +(1.-sig)*VR(HY_GAMC:HY_GAME) )
65
66End Subroutine hy_uhd_avgState

Download this code

In the above example you can see lines starting with a #. These lines don’t make any sense in Fortran itself, and would generate many errors if processed as is. Instead, these lines are handled by the preprocessor which modifies the source file before passing it on to the actual Fortran compiler. Take a look at these lines:

  • 33-34, 38-40, 45-46, and 57-59

Compiling, linking, and running a Fortran code

In the following we will use the sample code demo1.f90, presented below.

We can not run this directly the way we would for a MATLAB or Python script. Instead, it must be converted into object code, a version of the code that is in a machine language specific to the type of computer we are presently using. This is done by the compiler.

Then a linker must be used to convert the object code into an executable (or binary) that can actually be executed.

This is broken into two steps because often large programs are split into many different *.f90 files. Each one can be compiled into a separate object file, which by default has the same name but with a .o extension (for example, from demo1.f90 the compiler would produce demo1.o). One may also want to call on library routines that have already been compiled and reside in some library. The linker combines all of these into a single executable.

For more details on the process, see for example:

For the simplest case of a self-contained program in one file, we can combine both stages into a single call to gfortran, e.g.

$ gfortran demo1.f90

By default this will produce an executable named a.out for historical reasons (it stands for assembler output, see wikipedia).

To run the code you would then type

$ ./a.out

Note we type ./a.out to indicate that we are executing a.out from the current directory (see Basic Unix/Linux Commands). There is an environment variable PATH that contains your search path, the set of directories that are searched whenever you type a command name at the Unix prompt. This could feasibly be set so that the current directory is the first place searched, in which case you could just type a.out instead of ./a.out. However, it is generally considered bad practice to include the current directory on your path. Instead we need to specify the full path to the executable, which is conveniently done through the . alias for the current directory.

If you don’t like the name a.out you can specify an output name using the -o flag with the gfortran command. For example:

$ gfortran -o demo1.ex demo1.f90
$ ./demo1.ex

will also run the code.

Note that if you try one of the above commands, there will be no file demo1.o created. By default gfortran removes this file once the executable (e.g., demo1.ex, or a.out) is created.

Later, we will see that it is often useful to split up the compile and link steps, particularly if there are several files that need to be compiled and linked. We can do this using the -c flag to compile without linking:

$ gfortran -c demo1.f90              # produces demo1.o
$ gfortran -o demo1.ex demo1.o       # produces demo1.ex

There are many other compiler flags that can be used, see the gfortran man page for a list. Alternatively you can run man gfortran or info gfortran to get the same information directly.

Note

Linux doesn’t care very much what file extensions are used for different file types. You’ll notice that most text files have no extension, and that as above executables could be *.ex, *.out, blank, or really whatever you want.

I suggest using a consistent extension for executables so that they easier to put into your .gitignore file. I often use *.ex to indicate that a file is executable, but is not a Windows compatible binary.

Sample codes

The first example simply assigns some numbers to variables and then prints them out. The comments below the code explain some features.

 1! /codes/demo1.f90
 2! Fortran 90 program illustrating data types.
 3! Note that you should pick one convention, rather
 4! than mixing matching like this file does. This is
 5! just for illustration
 6
 7program demo1
 8
 9  implicit none
10  integer, parameter :: sp = selected_real_kind(6)
11  integer, parameter :: dp = selected_real_kind(15)
12  real :: x
13  real (sp) :: a
14  real (kind=dp) :: y,z
15  integer :: m
16  real (dp) :: i
17
18  ! Comment out implicit none and the declaration for i, then observe
19  ! what the following lines do:
20  ! i = 10
21  ! print*, i
22  ! i = 10.2394872938479287
23  ! print *,i
24  ! a = 1.3234
25  ! print*,a
26
27  m = 3
28  print *, " "
29  print *, "M = ", M   ! note that M is the same as m  (case insensitive)
30
31
32  print *, " "
33  print *, "x is real (kind=4)"
34  x = 1.0_sp + 1.23456789e-6_sp
35  print *, "x = ", x
36
37  print *, " "
38  print *, "a is also real (kind=4)"
39  x = 1.0_sp + 1.23456789e-6_sp
40  print *, "x = ", x
41
42
43  print *, " "
44  print *, "y is real (kind=8)"
45  print *, "  but 1.e0 is real (kind=4):"
46  y = 1.0_sp + 1.23456789e-6_sp
47  print *, "y = ", y
48
49
50  print *, " "
51  print *, "z is real (kind=8)"
52  print *, "  and 1.d0 is real (kind=8):"
53  ! The following line is equivalent to z = 1.d0 + 1.23456789d-6
54  z = 1.0_dp + 1.23456789e-6_dp
55  print *, "z = ", z
56
57end program demo1

Download this code

Comments:

  • Exclamation marks are used for comments

  • The implicit none statement in line 8 means that any variable to be used must be explicitly declared.

    Note

    Fortran has a very weird feature called implicit variables. With this feature, you don’t need to declare any variables! For instance, you can freely use any variables if you want, and variables name starts with i, j, k, l, m, n will be considered as an integer, and any other variables assumed to be a real number.

    This is an ancient feature for saving space on punched cards. But we are living in the 21st century, so we don’t need to use this troublesome feature anymore!

    Thus, I highly recommend to you to use implicit none statement on every Fortran file and routine to turn off the implicit feature, and make all variables you are using as explicit. Or, you can use compiler flag like -fimplicit-none (in gfortran) to force the compiler use implicit none statement on every single routine.

  • Lines 10 and 11 declare two integer constants sp and dp, which are used to enforce the precision of the floating point numbers used throughout. We will discuss floating point precision more soon.

  • Lines 12-15 declare five variables x, y, z, m, i. Note that x is declared to have type real which is a floating point number stored in 4 bytes, also known as single precision. This could have equivalently been written as

    real (kind=4) :: x
    ! Or
    real (kind=sp) :: x
    

    y and z are floating point numbers stored in 8 bytes (corresponding to double precision in older versions of Fortran). This is generally what you want to use.

  • Fortran is not case-sensitive, so M and m refer to the same variable!!

  • i declared on line 15 is also a double precision floating point real variable. Note that kind is implied and it suffices to type real (dp) :: i

  • 1.23456789e-10 specifies a 4-byte real number. The 8-byte equivalent is 1.23456789d-10, with a d instead of e. This is apparent from the output below.

  • Precision of floating point constants can be specified with a suffix of the form _p where p is an integer. This specification overrides the choice of e or d in scientific notation, and makes it more obvious what precision is desired. (See line 42 and 43)

Compiling and running this program produces

$ gfortran demo1.f90 -o demo1.ex
$ ./demo1.ex

 M =            3

 x is real (kind=4)
 x =    1.00000119

 y is real (kind=8)
   but 1.e0 is real (kind=4):
 y =    1.0000011920928955

 z is real (kind=8)
 z =    1.0000012345678899

For most of this class we will be using double precision real numbers and literals. We will discuss variable types in more detail later. Overall, you should specify real variables using a kind parameter set through a call to selected_real_kind(15) to guarantee the correct precision. For literals I prefer the suffix notation, but you can also use scientific notation with d instead of e.

(However, see Default 8-byte real numbers below for another approach.)

Intrinsic functions

There are a number of built-in functions that you can use in Fortran, for example the trigonometric functions:

 1! /codes/builtinfcns.f90
 2
 3program builtinfcns
 4
 5  implicit none
 6  integer, parameter:: fp = selected_real_kind(15)
 7  real (fp) :: pi, x, y
 8
 9  ! compute pi as arc-cosine of -1:
10  pi = acos(-1.0_fp)
11
12  x = cos(pi)
13  y = (exp(3.d0 * log(pi)))**(1.d0/3.d0)  ! need 3.d0 or 3.0_fp for double precision!
14
15  print *, "pi = ", pi
16  print *, "x  = ", x
17  print *, "y  = ", y
18
19end program builtinfcns

Download this code

This produces

$ gfortran builtinfcns.f90
$ ./a.out
 pi =   3.1415926535897931
 x  =  -1.0000000000000000
 y  =   3.1415926535897927

See http://www.nsc.liu.se/~boein/f77to90/a5.html for a good list of other intrinsic functions.

Default 8-byte real numbers

Note that you can declare variables to be real without appending (kind=8) if you compile programs with the gfortran flag -fdefault-real-8, e.g. if we modify the program above to:

 1! /codes/builtinfcns2.f90
 2
 3program builtinfcns
 4
 5  implicit none
 6  real :: pi, x, y
 7
 8  ! compute pi as arc-cosine of -1:
 9  pi = acos(-1.0)
10
11  x = cos(pi)
12  y = (exp(3.0 * log(pi)))**(1.0/3.0)
13
14  print *, "pi = ", pi
15  print *, "x  = ", x
16  print *, "y  = ", y
17
18end program builtinfcns

Download this code

Then

$ gfortran builtinfcns2.f90
$ ./a.out
 pi =   3.141593
 x =   -1.000000
 y =    3.141593

gives single precision results, but we can obtain double precision with

$ gfortran -fdefault-real-8 builtinfcns2.f90
$ ./a.out
 pi =   3.1415926535897931
 x =   -1.0000000000000000
 y =    3.1415926535897927

Fortran Arrays

Another good reference on Fortran arrays: Fortran Arrays and Strings

Note that arrays are indexed starting at 1 by default, rather than 0 as in Python or C. Also note that components of an array are accessed using parentheses, not square brackets!

Arrays can be dimensioned and used as in the following example:

 1! /codes/array1
 2
 3program array1
 4
 5  ! demonstrate declaring and using arrays
 6
 7  implicit none
 8  integer, parameter:: fp = selected_real_kind(15) ! Integer constant for precision
 9  integer, parameter :: m = 3, n = 2               ! Integer constants for array sizes
10  real (fp), dimension(m,n) :: A                   ! Rank 2 array (matrix 3 x 2)
11  real (fp), dimension(m) :: b                     ! Rank 1 array, size 3
12  real (fp), dimension(n) :: x                     ! Rank 1 array, size 2
13  integer :: i, j                                  ! Loop variables
14
15  ! Initialize matrix A and vector x:
16  ! Note that i and j get promoted to double precision on assignment into A
17  do j=1,n
18    do i=1,m
19      A(i,j) = i + j
20    end do
21    x(j) = 1.
22  end do
23
24  ! multiply A*x to get b:
25  do i=1,m
26    b(i) = 0.
27    do j=1,n
28      b(i) = b(i) + A(i,j)*x(j)
29    end do
30  end do
31
32  print *, "A = "
33  do i=1,m
34    print *, A(i,:)   ! i'th row of A
35  end do
36  print "(2d16.6)", ((A(i,j), j=1,2), i=1,3)
37  print *, "x = "
38  print "(d12.4)", x
39  print *, "b = "
40  print "(d16.6)", b
41
42end program array1

Download this code

Compiling and running this code gives the output

A =
  2.0000000000000000        3.0000000000000000
  3.0000000000000000        4.0000000000000000
  4.0000000000000000        5.0000000000000000
   0.200000D+01    0.300000D+01
   0.300000D+01    0.400000D+01
   0.400000D+01    0.500000D+01
x =
 0.1000D+01
 0.1000D+01
b =
   0.500000D+01
   0.700000D+01
   0.900000D+01

Comments:

  • In printing A we have used a slice operation: A(i,:) refers to the i’th row of A. In Fortran 90 there are many other array operations that can be done more easily than we have done in the loops above. We will investigate this further later.

    • See this article for more information about array slicing.

  • Here we set the values of m,n as integer parameters before declaring the arrays A,x,b. Being parameters means we can not change their values later in the program.

  • It is possible to declare arrays and determine their size later, using allocatable arrays, which we will also see later.

There are many array operations you can do, for example:

 1! /codes/vectorops.f90
 2
 3program vectorops
 4
 5  implicit none
 6  integer, parameter:: fp = selected_real_kind(15)
 7  real (fp), dimension(3) :: x, y
 8
 9  x = (/10.,20.,30./)
10  y = (/100.,400.,900./)
11
12  print *, "x = "
13  print *, x
14
15  print *, "x**2 + y = "
16  print *, x**2 + y
17
18  print *, "x*y = "
19  print *, x*y
20
21  print *, "sqrt(y) = "
22  print *, sqrt(y)
23
24  print *, "dot_product(x,y) = "
25  print *, dot_product(x,y)
26
27
28end program vectorops

Download this code

produces

x =
  10.000000000000000        20.000000000000000        30.000000000000000
x**2 + y =
  200.00000000000000        800.00000000000000        1800.0000000000000
x*y =
  1000.0000000000000        8000.0000000000000        27000.000000000000
sqrt(y) =
  10.000000000000000        20.000000000000000        30.000000000000000
dot_product(x,y) =
  36000.000000000000

Note that addition, multiplication, exponentiation, and intrinsic functions such as sqrt all apply component-wise.

Multidimensional arrays can be manipulated in similar manner. The product of two arrays x and y using * (i.e., x*y) is always component-wise. For matrix multiplication, use matmul. There is also a transpose function:

 1! /codes/arrayops.f90
 2
 3program arrayops
 4
 5  implicit none
 6  integer, parameter:: fp = selected_real_kind(15)
 7  real(fp), dimension(3,2) :: a
 8  real(fp), dimension(2,3) :: b
 9  real(fp), dimension(3,3) :: c
10  real(fp), dimension(2) :: x
11  real(fp), dimension(3) :: y
12  integer :: i
13
14  a = reshape((/1,2,3,4,5,6/), (/3,2/))
15
16  print *, "a = "
17  do i=1,3
18    print *, a(i,:)   ! i'th row
19  end do
20
21  b = transpose(a)
22
23  print *, "b = "
24  do i=1,2
25    print *, b(i,:)   ! i'th row
26  end do
27
28  c = matmul(a,b)
29  print *, "c = "
30  do i=1,3
31    print *, c(i,:)   ! i'th row
32  end do
33
34  x = (/5,6/)
35  y = matmul(a,x)
36  print *, "x = ",x
37  print *, "y = ",y
38
39end program arrayops

Download this code

produces

a =
  1.0000000000000000        4.0000000000000000
  2.0000000000000000        5.0000000000000000
  3.0000000000000000        6.0000000000000000
b =
  1.0000000000000000        2.0000000000000000        3.0000000000000000
  4.0000000000000000        5.0000000000000000        6.0000000000000000
c =
  17.000000000000000        22.000000000000000        27.000000000000000
  22.000000000000000        29.000000000000000        36.000000000000000
  27.000000000000000        36.000000000000000        45.000000000000000
x =    5.0000000000000000        6.0000000000000000
y =    29.000000000000000        40.000000000000000        51.000000000000000

Comments:

  • Take note of the order of elements in a (line 14)

  • The matmul function works for both matrix-matrix multiplication and matrix-vector multiplication (lines 21 and 28)

  • Writing a literal array starts with (/ and finishes with /) (lines 14 and 34)

Loops

Consider a code with do-loops:

 1! /codes/loops1.f90
 2
 3program loops1
 4
 5  implicit none
 6  integer :: i
 7
 8  do i=1,3           ! prints 1,2,3
 9    print *, i
10  end do
11
12  do i=5,11,2        ! prints 5,7,9,11
13    print *, i
14  end do
15
16  do i=6,2,-1        ! prints 6,5,4,3,2
17    print *, i
18  end do
19
20  i = 0
21  do while (i < 5)   ! prints 0,1,2,3,4
22    print *, i
23    i = i+1
24  end do
25
26end program loops1

Download this code

If you need a loop that will be executed an unknown number of times, it may better to use a do loop with a cap on the maximum number of iterations and an exit statement. The last loop could be rewritten as:

 1! /codes/loops2.f90
 2
 3program loops2
 4
 5  implicit none
 6  integer :: i,j,jmax
 7
 8  i = 0
 9  jmax = 100
10  do j=1,jmax        ! prints 0,1,2,3,4
11    if (i>=5) exit
12    print *, i
13    i = i+1
14  end do
15
16  if (j==jmax+1) then
17    print *, "Warning: jmax iterations reached."
18  end if
19
20end program loops2

Download this code

Note: j is incremented before comparing to jmax.

if-then-else

 1! /codes/ifelse1.f90
 2
 3program ifelse1
 4
 5  implicit none
 6  integer, parameter:: fp = selected_real_kind(15)
 7  real (fp) :: x
 8  integer :: i
 9
10  if (i<=2) then
11    print *, "i is less or equal to 2"
12  else if (i/=5) then
13    print *, "i is greater than 2 but not equal to 5"
14  else 
15    print *, "i is equal to 5"
16  end if
17
18  x = sqrt(2.0_fp)
19  if (x<2) then
20    print *, "x is less than 2"
21  else
22    print *, "x is not less than 2"
23  end if
24
25end program ifelse1

Download this code

Comments:

  • The else clause is optional

  • You can have multiple optional else if clauses

There is also a one-line form of an if statement that may be useful. Note that you can not follow the statement with additional else if or else statements.

if (x<2) exit

This is equivalent to

if (x<2) then
   exit
end if

Booleans

  • Compare with <, >, <=, >=, ==, /=. You can also use the older Fortran 77 style: .lt., .gt., .le., .ge., .eq., .neq..

  • Combine with .and. and .or.

For example

((x>=1.0) .and. (x<=2.0)) .or. (x>5)

A boolean variable is declared with type logical in Fortran, as in the following code:

 1! /codes//boolean1.f90
 2
 3program boolean1
 4
 5  implicit none
 6  integer :: i,k
 7  logical :: ever_zero
 8  real :: myTrulyTrulyVeryLongVariableNameToStoreRealVariable
 9  real :: a, b
10
11  ever_zero = .false.
12  do i=1,10
13    k = 3*i - 1
14    print*, i, k, ever_zero, (k == 0)
15    ever_zero = (ever_zero .or. (k == 0))
16  end do
17
18  if (ever_zero) then
19    print *, "3*i - 1 takes the value 0 for some i"
20  else
21    print *, "3*i - 1 is never 0 for i tested"
22  end if
23
24  a = 1.0
25  myTrulyTrulyVeryLongVariableNameToStoreRealVariable = 2.0
26  b = a + myTrulyTrulyVeryLong&
27      &VariableNameToStoreRealVariable
28
29  print*,a,b
30end program boolean1

Download this code

Line Continuation

You can split very long lines into multiple lines using the & operator. This is potentially useful for single line conditional statements like:

if (i>=5) &
   print *, 'This line is too long and I am using & to continue. This is handy!!!'

If you really wish you were writing enterprise grade Java code and want to use an absurdly long variable name, you could split it off and continue it on another line (please don’t actually do this):

real :: myTrulyTrulyVeryLongVariableNameToStoreRealVariable
real :: a, b

a = 1.0
myTrulyTrulyVeryLongVariableNameToStoreRealVariable = 2.0
b = a + myTrulyTrulyVeryLongVariableNameToStoreRealVariable

or, the last can be put into two lines using &

b = a + myTrulyTrulyVeryLong&
        &VariableNameToStoreRealVariable

But, in this case, make sure that there is no space between the last character Long and the & that follows it

b = a + myTrulyTrulyVeryLong   &
        &VariableNameToStoreRealVariable

This will be then equivalent to

b = a + myTrulyTrulyVeryLong   VariableNameToStoreRealVariable

which is not what you wanted to do.

The situation is the same with the second line that follows the first line

b = a + myTrulyTrulyVeryLong&
    &      VariableNameToStoreRealVariable

Note

Line continuation is mostly a hold over from the Fortran 77 fixed formatting days. For the most part, I would advise that you write code in a way that doesn’t need continuation.