Variables
Last updated on 2026-02-21 | Edit this page
Overview
Questions
- What are some basic types of numeric variables in Fortran?
- How are variables declared and defined?
- How do I create constants?
Objectives
- Understand how to create variables and assign values to them.
- Specify the representation in memory of variables independently of the implementation.
- Store constant values.
Numeric variables of intrinsic type
The following program declares a variable with each of the three intrinsic numeric types, and provides an initial value in each case.
FORTRAN
program example1
implicit none
integer :: i = 1 ! A default integer kind
real :: a = 2.0 ! A default floating point kind
complex :: z = (0.0, 1.0) ! A complex kind with (real-part, imag-part)
end program example1
Initial values are optional. If a declaration does not specify an initial value, the variable is said to be undefined.
Variable names
The valid Fortran character set for names is a-z,
A-Z, 0-9 and the underscore _.
Valid names must begin with a character. The maximum length of a name is
63 characters (F2003) with no spaces allowed. This includes names for
programs, and names for variables.
Other special characters recognised by Fortran are:
| Character | Name | Character | Name |
|---|---|---|---|
| Blank | ; |
Semi-colon | |
= |
Equals | ! |
Exclamation mark |
+ |
Plus | " |
Double quote |
- |
Minus | % |
Percent |
* |
Asterick | & |
Ampersand |
/ |
Slash | ~ |
Tilde |
\ |
Backslash | < |
Less than |
( |
Left parenthesis | > |
Greater than |
) |
Right parenthesis | ? |
Question mark |
[ |
Left square bracket | ' |
Apostrophe |
] |
Right square bracket | ` |
Grave accent |
{ |
Left curly brace | ^ |
Circumflex |
} |
Right curly brace | | |
Pipe |
, |
Comma | $ |
Dollar sign |
. |
Decimal point | # |
Hash |
: |
Colon | @ |
At |
Other characters may appear in comments.
implicit statement
The implicit statement defines a type for variable names
not explicitly declared. So, the default situation can be represented
by
that is, variables with names beginning with letters i-n
are implicitly of type integer, while anything else is of
type real (unless explicitly declared otherwise).
By modern standards this is tantamount to recklessness. The general solution to prevent errors involving undeclared variables (usually arising from typos) is to declare that no names have implicit type via
In this case, all variable names must be declared explicitly before they are referenced.
However, it is still common to see the idiom that variables beginning
with i-n are integers and so on, albeit declared
explicitly.
Using implicit none
To reiterate – all modern Fortran code really should use
implicit none. Failing to do so will almost certainly lead
to bugs and hence time spent debugging!
Exercise (1 minute)
The importance of being explicit
Compile and run the accompanying program exercise1.f90. What’s the problem and how should we avoid it? Check the compiler can trap the problem.
The issue is that the variable we declare is initialise is
ll, but the variable we print is l1. Look
closely at these names: the latter mistakenly uses a digit one
1 where it should be the letter l. When we
print the hitherto unmentioned l1, the compiler implicitly
creates it as a new integer.
Add implicit none to the top of the code
FORTRAN
program exercise1
implicit none
integer :: ll = 1
print *, "The value of ll is: ", l1
end program exercise1
which then produces an error at compile time, e.g. with the Cray compiler:
OUTPUT
print *, "The value of ll is: ", l1
^
ftn-113 ftn: ERROR EXERCISE1, File = exercise1.f90, Line = 7, Column = 36
IMPLICIT NONE is specified in the local scope, therefore an explicit type must be specified for data object "L1".
Cray Fortran : Version 15.0.0 (20221026200610_324a8e7de6a18594c06a0ee5d8c0eda2109c6ac6)
Cray Fortran : Compile time: 0.0024 seconds
Cray Fortran : 9 source lines
Cray Fortran : 1 errors, 0 warnings, 0 other messages, 0 ansi
Cray Fortran : "explain ftn-message number" gives more information about each message.
kind of type
The declarations above give us variables of some
(implementation-defined) default type (typically 4-byte integers, 4-byte
reals). A mechanism to control the exact kind, or representation, is
provided. For example (see example2.f90),
FORTRAN
use iso_fortran_env, only : int64, real64
implicit none
integer (kind = int64) :: i = 100
real (kind = real64) :: a = 1.0
complex (kind = real64) :: z = (0.0, 1.0)
Here we use kind type parameters int64 and
real64 to specify that we require 64-bit integers and
64-bit floating point storage, respectively.
A standard conforming Fortran implementation must provide at least
one integer precision with a decimal exponent range of at
least 18 (experience suggests all provide at least two kinds). Note that
Fortran does not have any equivalent of C/C++ unsigned integer
types.
An implementation must provide at least two real
precisions, one default precision, and one extended precision (sometimes
referenced as double precision).
Formally, the numeric types are introduced
where the numeric-type-spec is one of
integer, real, or complex. The
optional kind selector is
The upshot of this is that the syntax of declarations is quite elastic, and you may see a number of different styles. A reasonable form of concise declaration with an explicit kind type parameter is:
Example (2 minutes)
Take a moment to compare the output of the programs example1.f90 and example2.f90, which declare and initialise a variable of each type and print out their values to the screen.
Numeric literal constants
One may (optionally) specify the kind of an integer literal by
appending the kind type parameter with an underscore _,
e.g.:
Floating point literal constants can take a number of forms. Examples are:
FORTRAN
-3.14
.314
1.0e0 ! default precision
1.0d0 ! extended (double) precision
3.14_real128 ! may be available
3.14e-1 ! Scientific notation
3.14d+1 ! Scientific notation extended precision
Complex literals are constructed with real and imaginary parts, with each part real.
Parameters
Suppose we did not want to hardwire our kind type parameters throughout the code. Consider:
FORTRAN
program example3
implicit none
integer, parameter :: my_e_k = kind(1.e0)
integer, parameter :: my_d_k = kind(1.d0)
real (my_e_k) :: a
real (my_d_k) :: b
! ...
end program example3
Here we have introduced an integer with the
parameter attribute. This is an instruction to the
compiler that the associated name should be a constant (similar to a
const declaration in C). Any subsequent attempt to assign a
value to a parameter will result in a compile time error.
The value specified in the parameter declaration must be a constant
expression (which the compiler may be able to evaluate at compile time).
Here we have made use of the intrinsic function
kind(). The kind() function returns an integer
which is the kind type parameter of the argument. In this context a
constant expression is one in which all parts are intrinsic.
Note we have not included anything or use’d anything to
make this kind() function available. It is an intrinsic
function and part of the language itself.
Using a parameter provides a degree of abstraction for the real data type. Other examples might include:
FORTRAN
integer, parameter :: nmax = 32 ! A constant
real, parameter :: pi = 4.0*atan(1.e0) ! A well-known constant
complex, parameter :: zi = (0.0, 1.0) ! square root of -1
The intrinsic function atan() returns the inverse
tangent (as a value in radians) of the argument.
Exercise (2 minutes)
Challenge
Consider further the accompanying example3.f90, where
we have introduced another intrinsic function
storage_size() (roughly equivalent to C’s
sizeof() although it returns a size in bits rather than
bytes). Run the program and check the actual values of the kind type
parameters and associated storage sizes. Speculate on the portability of
a program declaring, e.g.:
Exercise (2 minutes)
Parameters
Consider the accompanying exercise2.f90. Check the compiler error emitted and remove the offending line.
Arithmetic operations on numeric types
For all intrinsic numeric types, standard arithmetic operations,
addition (+), subtraction (-), multplication
(*) and division (/) are defined, along with
exponents (**) and negation (-).
In order of increasing precedence these are -,
+, /, *, and **
(otherwise left-to-right). In particular
Use parentheses to avoid ambiguity if necessary.
A large number of intrinsic functions exist for basic mathematical
operations and are relevant for all numeric types. A simple example is
sqrt(). Some are specific to particular types, e.g.,
conjg() for complex conjugate.
Broadly, assignments featuring different data types will cause promotion to a “wider” type or cause truncation to a “narrower” type. If one wants to be explicit, the equivalent of the cast mechanism in C is via intrinsic functions, e.g.,
FORTRAN
integer :: i = 1
complex (real64) :: z = (1.0, 1.0)
real (real64) :: a, b
a = real(i, real64) ! a should be 1.d0
a = real(z, real64) ! imaginary part is ignored
b = real(i) ! return default real kind
z = cmplx(a, b) ! (sic) Form complex number from two reals
The second argument of the real() function is optional,
and specifies the kind type parameter of the desired result. If the
optional argument is not present, then a real value of the default kind
is returned.
Note here the token real has been used in two
different contexts: as a statement in the declaration of variables
a and b, and as a function. There is not quite
the same concept of “reserved words” (cf C/C++); lines are split into
tokens based on spaces, and tokens are parsed in context.
Complex real and imaginary parts
The real and imaginary parts of a complex variable may be accessed
where the % symbol is referred to as the component
selector. The real and imaginary parts are also available via the
real() and aimag() intrinsic functions,
respectively.
Exercise (2 minutes)
Using sqrt()
By using variables of complex type, check that you can use the
intrinsic function srqt() to confirm that the square root
of -1 is i. What happens if you try to try to take the
square root of a negative value stored as a real variable?
If you call sqrt() on a complex variable
z%re = -1.0 and z%im = 0.0 then a result will
be returned with a real part of 0 and an imaginary part of
1.
If you call sqrt() on a real number -1 then
the compiler will exit with an error and a message explaining why this
is not valid. If sqrt() is called on a variable with the
value -1 it will return NaN.
Exercise (5 minutes)
Calculating pi
The accompanying template exercise3.f90 provides instructions for an exercise which involves the approximation to the constant pi computed via a Gauss-Legendre algorithm. Some background can be found at https://en.wikipedia.org/wiki/Gauss-Legendre_algorithm.
Use the instructions in the template to calculate an estimate of pi
by creating an appropriate parameter to store a kind,
declaring the appropriate variables, then performing the calculation and
printing the values of pi.
A solution to this problem appears as the template for the first exercise in the episode on loops.
Exercise (5 minutes)
Calculating the conductance in a narrow channel
A second exercise in a similar vein looks at an approximation to the conductance of a rectangular channel subject to a constant flow. Instructions are in exercise4.f90.
As with the previous exercise, create a kind, the
variables, then perform the necessary arithmetic to calculate
C_1.
A solution to this problem appears as the template for the second exercise in the episode on loops.
- Fortran provides the intrinsic numeric types of
integer,realandcomplex. - Without a
kind, these types are implementation-defined. Usekindto specify the representation of variables. - The
iso_fortran_envintrinsic module provides standard kinds such asreal32andreal64. - Always use
implicit noneto prevent the accidental implicit declaration of new variables. - Use the
parameterattribute to make the value associated with the name constant.