Clicky

Fortran Wiki
literal and constant

Constants

In Fortran, constants are fixed values that cannot be changed during program execution.

Constants can be defined in two ways:

Literals or literal constants: Unnamed constants directly representing values used directly in the code, where the compiler infers the type from the form (e.g., 123, 1.5, (1.0, 2.0), “Hello!”, etc.).

Named constants: Declared using the PARAMETER statement, assigning a symbolic name to a constant value.

Key reasons to use constants:

Using constants, particularly named constants offers several significant advantages related to code quality, safety, performance, and maintenance.

Improved Readability and Clarity: By replacing “magic numbers” (unexplained numerical values) with descriptively named constants (e.g., using PI instead of 3.14159), the code becomes more self-documenting and easier for developers to understand.

Easier Maintenance: If a constant value needs to be updated (e.g., an array size or variable kind or error message, …), the change only has to be made in a single place (the constant definition), rather than searching for and updating every instance throughout the code. This minimizes the risk of errors from missed updates.

Prevents Accidental Modification: Declaring a value as a constant can prevent it from being unintentionally changed during program execution. The compiler will generally flag an error if a modification is attempted, which helps catch bugs early in the development process.

Compiler Optimization: The compiler can perform better optimizations when it knows a value will not change during runtime. For example, the compiler can use techniques like constant folding or place the constant in read-only memory, potentially leading to faster and more efficient code execution, particularly when large tables of constants are involved that require significant computational time to calculate.

Ensures Data Integrity: Constants ensure that important, fixed values (like physical constants such as the speed of light or mathematical constants like pi) remain consistent and uncorrupted throughout the program’s lifecycle. This is crucial for numerical and scientific applications where precision and consistency are vital.

Types of Fortran Literal Constants

Literal constants are typically one of the basic data types: integer, real (floating point), complex, logical, and character strings but can be expressions using most intrinsics and intrinsic operators as well.

Integer: A string of digits with an optional sign. Commas or decimal points are not allowed. 0, -345, +12345

Real: Represents floating-point numbers. Must have a decimal point or an exponent part (using E, D, or a KIND suffix for different precision levels). 23.45, .123, 123., -0.12, 1.0E-02, 123.456_real64, …

Complex: An ordered pair of integer or real constants enclosed in parentheses, representing the real and imaginary parts. (1.0, 2.0), (0, 1)

Logical: Represents a Boolean value. There are only two logical constants. .TRUE., .FALSE.

Character: A sequence of characters enclosed in single quotes (’) or double quotes (“). ‘Hello World’, ”A string“, ‘’ (empty string)

Named Constants (Parameters)

To create a named constant, you use the PARAMETER attribute in a type declaration statement. It may then subsequently be used in defining additional constants (and variables) in the same scope.

The values of named constants are often literal constants.

Built-in pre-defined constants

There are a number of constants defined in intrinsic modules included with Fortran. The most commonly used are in the modules iso_fortran_env and iso_c_binding.

Common examples include

! KIND related
use,intrinsic :: iso_fortran_env,only : int8,int16,int32,int64
use,intrinsic :: iso_fortran_env,only : integer_kinds
use,intrinsic :: iso_fortran_env,only : real32,real64,real128
! examples renaming the constants ...
use,intrinsic :: iso_fortran_env,only : wp => real64
use,intrinsic :: iso_fortran_env,only : sp => real32, dp =>real64

! I/O Error codes
use,intrinsic :: iso_fortran_env,only : iostat_eor,iostat_end

! KIND related information for interfacing to C
use,intrinsic :: iso_c_binding,only : C_BOOL

! Unit numbers of pre-assigned I/O units
use,intrinsic :: iso_fortran_env,only : stderr=>ERROR_UNIT
use,intrinsic :: iso_fortran_env,only : stdin=>input_unit
use,intrinsic :: iso_fortran_env,only : stdout=>output_unit

Example program declaring named constants (read the comments!) :

program named_constants
! some pre-defined constants
use,intrinsic :: iso_fortran_env,only : int8,int16,int32,int64, &
                                        real32,real64,real128
use,intrinsic :: iso_fortran_env,only : stderr=>ERROR_UNIT, &
                                        stdin=>input_unit, &
                                        stdout=>output_unit
implicit none

integer,parameter  :: dp=kind(0.0d0)
! DP can now be used in subsequent constant (and variable) declarations
! if subsequent variables are declared using this KIND value only one
! line may need changed to create a procedure to handle another variable
! size (this can often be done using a pre-processor such as cpp(1)/fpp(1),
! simplifying creating generic procedures).

real(dp),parameter :: PI=3.14159265358979323846264338327950_dp
! notice the KIND suffix on the literal value. Even that does not
! guarantee all the digits will be retained, but without it only
! the digits contained in a default REAL would be required to be significant
! because the RHS is evaluated first, _then_ promoted to the LHS value.
!
! to (possibly) prove a point:
real(dp),parameter :: PIE=3.14159265358979323846264338327950
! your compiler might have an extension, but by the standard PIE will
! only be required to have nine accurate digits (assuming the default
1 read is a typical 32-bit float).
!
! An intentional error:
! the RHS is double-precision, but the LHS is only single-precision
real,parameter :: TART=acos(-1.0_dp)

! nice abbreviations to use in subsequent statements
logical, parameter :: T=.true., F=.false.
! potentially save space and improve performance by using the
! smallest available LOGICAL kind for large logical arrays
integer,parameter :: lk=selected_logical_kind(1)
logical(lk)       :: smallest_storage(1000,20)

! expressions using most intrinsics and arithmetic operators can be used
! to define a constant. Note the use of the CHAR(3) function
character(len=*), parameter :: esc=char(27)

! ANSI terminal escape sequence to clear screen and home cursor
! using ESC and a character expression (using concatenation):
character(len=*), parameter :: clear= esc//'[H'//esc//'[2J'//esc//'[3J'

! let us not forget complex values
complex,parameter :: py = (3.0,4.0)

! creating a constant user-defined type. The TYPE declaration cannot
! directly contain named constants although it can contain initial
! values
real,parameter :: huge_neg=(-1.0)-huge(0.0)
type point
   real :: x=huge_neg, y=huge_neg, z=huge_neg
end type point
! but an instance of the type can still be a constant
type(point), parameter :: origin=point(0.0,0.0,0.0)

! a common use with user types is to create an "enumerator" object:
type color
   integer :: red,green,blue,yellow,cyan,magenta,black,white
end type color
type(color),parameter:: primary=color(0,1,2,3,4,5,6,7)

! a common use of character constants is for formats
character(len=*),parameter :: gen='(*(g0))'
character(len=*),parameter :: gap='(*(g0,1x))'

! the maligned NEW_LINE(3) function can be quite useful
character(len=*),parameter :: nl=new_line('A')

   print gen, clear
   print gen, 'how many digits are accurate?'
   print gen, 'PI= 3.14159265358979323846264338327950...'
   print gen, 'PI=  ',PI, nl, 'PIE= ',PIE, nl, 'TART=',TART
   print gen, 'Be Kind Constantly!'
   print gap, nl, 'RGB=',primary%red,primary%green,primary%blue
   print gen, nl, 'ABS(3) calculates the distance from the origin'
   print gen, 'abs( (',py%re,',',py%im,') )=',abs(py)
   print gen, nl, 'George Washington ', nl, &
                  'could not tell a', nl, F,'ib. ', &
                  [F,F,F,F,F,T,T,T],'!'

end program named_constants

Expected output:

    \e[H\e[2J\e[3J
    how many digits are accurate?
    PIE= 3.14159265358979323846264338327950...
    PI=  3.1415926535897931
    PIE= 3.1415927410125732
    TART=3.14159274
    Be Kind Constantly!

     RGB= 0 1 2

    ABS(3) calculates the distance from the origin
    abs( (3.00000000,4.00000000) )=5.00000000

    George Washington
    could not tell a
    Fib. FFFFFTTT!

Type Specification Nuances

Kinds

Fortran 90 and later versions allow specifying the data kind (precision/size) of a literal constant using an underscore followed by the kind parameter for all types except CHARACTER, where the kind is prefixed instead.

Most common error when defining constants

The most common error when defining constants is to not specify a literal constant on the right-hand side (RHS) to have the correct kind, often leading to a loss of precision in the named constants’ value.

An internal READ cannot read from a constant variable

You cannot use a CHARACTER constant as the target for an internal READ(). You can use a SAVEd variable instead (nb.: variables appearing in a DATA statement are automatically saved values, for better or for worse.)

Constant Naming Conventions

A common convention is to use all capital letters for the names of named constants but there is nothing in standard Fortran that will enforce this. Others use an unusual suffix as “_Q” or even “__”, but again as a convention not as anything the compiler will enforce.

Passing constants as arguments

Another of the most common constant-related errors with undefined effects is to pass a constant as an argument to a procedure that changes the value. If constants are passed to a non-intrinsic procedure it is preferred that the procedure declared that parameter as INTENT(IN) explicitly. One platform may produce no ill effects, while another might change the value of a constant, so that references to “1” in other parts of the code may now use another value, for example!

User-defined types as constants

A user-defined TYPE definition itself may not declare constant components, but that does not preclude creating instances of that type that are constants. A common use of this is to create “enumerated” variables; but newer versions of Fortran has two enumerated types now as well.

Additional notes on character constants

An apostrophe character within a character constant delimited by apostrophes is represented by two consecutive apostrophes (without intervening blanks); in this case, the two apostrophes are counted as one character. Similarly, a quotation mark character within a character constant delimited by quotation marks is represented by two consecutive quotation marks (without intervening blanks) and the two quotation marks are counted as one character.

A zero-length character literal constant is represented by two consecutive apostrophes(without intervening blanks) or two consecutive quotation marks (without intervening blanks) outside of a character context.

Examples of character literal constants are:

 character(len=*),parameter :: dont="DON’T"
 character(len=*),parameter :: dont=’DON’’T’

both of which have the value DON’T and

 character(len=*),parameter :: nil=’’

which has the zero-length character string as its value.

If using the optional Unicode CHARACTER kind “ISO_10646” remember that the UCS-4 kind is a prefix not a suffix on literal constants:

program fortran_unicode
use,intrinsic :: iso_fortran_env, only: stdout => output_unit
implicit none
integer,parameter :: ucs4 = selected_char_kind('ISO_10646')
character(kind=ucs4,len=:),allocatable :: ustr2
! ISO-10646 ENCODING:己所不欲,勿施於人
character(len=*,kind=ucs4),parameter :: ustr= &
ucs4_"The Silver Rule: "// &
ucs4_"What you do not want done to yourself, do not do to others, or "// &
char(int(z'5DF1'),kind=ucs4)// &
char(int(z'6240'),kind=ucs4)// &
char(int(z'4E0D'),kind=ucs4)// &
char(int(z'6B32'),kind=ucs4)// &
char(int(z'FF0C'),kind=ucs4)// &
char(int(z'52FF'),kind=ucs4)// &
char(int(z'65BD'),kind=ucs4)// &
char(int(z'65BC'),kind=ucs4)// &
char(int(z'4EBA'),kind=ucs4)
   open(stdout,encoding='utf-8')
   write(stdout,*)ustr
end program fortran_unicode

Output:

 The Silver Rule: What you do not want done to yourself,
 do not do to others, or 己所不欲,勿施於人

Hollerith constants

Holleriths, named in honor of Herman Hollerith, were used in early FORTRAN programs to allow manipulation of character data. They should be replaced by quoted strings. There are utility programs, both commercial and free, that will aid in the modernization. See

https://en.wikipedia.org › wiki › Hollerith_constant

See Also:

  • PROTECT for creating values that cannot be changed outside of a module
  • ASSOCIATE creating a constant value in the scope of a block of code