ZetCode

Fortran data types and kinds

last modified November 14, 2026

Fortran has five intrinsic data types: integer, real, complex, logical, and character. Each type comes in one or more kinds, which select the size and precision of the values. This article describes the types, shows how to choose a kind in a portable way, and looks at the limits of integers and floating-point numbers.

Intrinsic types

The table lists the five types. Derived types, which programmers define themselves, are described in a later article.

TypeHoldsExample declaration
integerwhole numbersinteger :: count
realfloating-point numbersreal :: height
complexpairs of real numberscomplex :: z
logical.true. or .false.logical :: done
charactertext of a given lengthcharacter(len=20) :: name

A kind is written in parentheses after the type name, for example integer(kind=8) or just integer(8). A declaration without a kind uses the default kind of the type. The function kind returns the kind of a variable, so we can ask the compiler what the defaults are.

Default kinds

Kinds are small integers, and the standard does not say what they mean; every compiler chooses its own numbers. The program prints the default kind of every type. It also declares a variable of type double precision, the old way of asking for a real number with more than the default precision.

kinds.f90
program kinds
    implicit none
    integer :: i
    real :: r
    double precision :: d
    complex :: z
    logical :: flag
    character(len=5) :: s

    print *, 'integer:          ', kind(i)
    print *, 'real:             ', kind(r)
    print *, 'double precision: ', kind(d)
    print *, 'complex:          ', kind(z)
    print *, 'logical:          ', kind(flag)
    print *, 'character:        ', kind(s)
end program kinds

In gfortran the kind number of an integer, real or logical equals the number of bytes the value takes, so the default integer and real have 4 bytes (32 bits) and double precision has 8. A default complex number is a pair of default reals, and a character has kind 1. Other compilers number kinds differently, so a program should never depend on the numbers themselves.

$ gfortran kinds.f90 -o kinds
$ ./kinds
 integer:                     4
 real:                        4
 double precision:            8
 complex:                     4
 logical:                     4
 character:                   1

Kind constants of iso_fortran_env

The intrinsic module iso_fortran_env provides named constants for the sizes in bits: int8, int16, int32, int64 for integers and real32, real64, real128 for reals. They are the portable way to say "a 64-bit integer" or "a double-precision real".

envkinds.f90
program envkinds
    use, intrinsic :: iso_fortran_env, only: int8, int16, int32, int64, &
                                             real32, real64, real128
    implicit none

    print *, 'int8:   ', int8
    print *, 'int16:  ', int16
    print *, 'int32:  ', int32
    print *, 'int64:  ', int64
    print *, 'real32: ', real32
    print *, 'real64: ', real64
    print *, 'real128:', real128
end program envkinds

The program imports the constants with use, intrinsic and prints them. In gfortran they are the byte sizes, so real64 is 8, and the 128-bit real is available as kind 16. The names are what the program should use: real(real64) reads as a declaration of a 64-bit real on every compiler, whatever number it uses internally.

$ gfortran envkinds.f90 -o envkinds
$ ./envkinds
 int8:              1
 int16:             2
 int32:             4
 int64:             8
 real32:            4
 real64:            8
 real128:          16

Integers

An integer is a signed whole number. The function huge returns the largest value of the kind of its argument. The literal 1_int8 used below is an integer of kind int8; the suffix syntax is described in the literals article.

limits.f90
program limits
    use, intrinsic :: iso_fortran_env, only: int8, int16, int32, int64
    implicit none

    print *, 'int8:  ', huge(1_int8)
    print *, 'int16: ', huge(1_int16)
    print *, 'int32: ', huge(1_int32)
    print *, 'int64: ', huge(1_int64)
end program limits

An 8-bit integer reaches 127, a 16-bit integer 32767, a 32-bit integer 2147483647, and a 64-bit integer 9223372036854775807. Fortran has no unsigned integer types in the standard, so these are all signed ranges.

$ gfortran limits.f90 -o limits
$ ./limits
 int8:    127
 int16:   32767
 int32:   2147483647
 int64:   9223372036854775807

Integer overflow

When a result does not fit the kind, the standard says nothing about what happens, and the compiler is free to do anything. In practice the value wraps around, and the program continues with a wrong number.

overflow.f90
program overflow
    implicit none
    integer :: i

    i = huge(i)
    print *, 'largest: ', i
    i = i + 1
    print *, 'plus one:', i
end program overflow

The program stores the largest value in i and adds one. The result is the most negative value. The run-time checks enabled by -fcheck=all do not catch integer overflow. Compiling with -ftrapv makes the same program abort with a signal at the addition instead, which is useful while testing. When a computation can exceed 32 bits, choose a wider kind such as int64.

$ gfortran overflow.f90 -o overflow
$ ./overflow
 largest:   2147483647
 plus one: -2147483648

Reals

A real holds a floating-point number. The functions huge, tiny, epsilon, precision and range describe a real kind: huge is the largest finite value, tiny the smallest positive normal value, epsilon the smallest number that changes 1.0 when added to it, precision the number of reliable decimal digits, and range the decimal exponent range.

reallimits.f90
program reallimits
    use, intrinsic :: iso_fortran_env, only: real32, real64
    implicit none
    real(real32) :: s
    real(real64) :: d

    print *, 'real32 huge:     ', huge(s)
    print *, 'real32 tiny:     ', tiny(s)
    print *, 'real32 epsilon:  ', epsilon(s)
    print *, 'real32 precision:', precision(s)
    print *, 'real32 range:    ', range(s)
    print *, 'real64 huge:     ', huge(d)
    print *, 'real64 tiny:     ', tiny(d)
    print *, 'real64 epsilon:  ', epsilon(d)
    print *, 'real64 precision:', precision(d)
    print *, 'real64 range:    ', range(d)
end program reallimits

A 32-bit real has about 6 reliable decimal digits and values up to about 3.4e38. A 64-bit real has about 15 digits and reaches 1.8e308. The epsilon values, about 1.2e-7 and 2.2e-16, are the relative size of the gap between neighbouring numbers: they show why single precision is rarely enough for scientific work. gfortran writes the exponent of a 64-bit real with three digits, such as E-016, in list-directed output.

$ gfortran reallimits.f90 -o reallimits
$ ./reallimits
 real32 huge:        3.40282347E+38
 real32 tiny:        1.17549435E-38
 real32 epsilon:     1.19209290E-07
 real32 precision:           6
 real32 range:              37
 real64 huge:        1.7976931348623157E+308
 real64 tiny:        2.2250738585072014E-308
 real64 epsilon:     2.2204460492503131E-016
 real64 precision:          15
 real64 range:             307

Representation errors

Most decimal fractions have no exact binary representation. The number 0.1 is stored as the closest binary fraction, and the error is larger in single precision. The program writes the stored values with 18 significant digits in scientific notation (the edit descriptor es26.17e3) and compares a sum.

precision.f90
program precision_demo
    use, intrinsic :: iso_fortran_env, only: real32, real64
    implicit none
    real(real32) :: s = 0.1_real32
    real(real64) :: d = 0.1_real64

    write (*, '(a, es26.17e3)') 'real32 0.1 = ', s
    write (*, '(a, es26.17e3)') 'real64 0.1 = ', d
    write (*, '(a, l1)') '0.1 + 0.2 == 0.3 (real64): ', 0.1_real64 + 0.2_real64 == 0.3_real64
    write (*, '(a, es26.17e3)') '0.1 + 0.2 - 0.3 =      ', 0.1_real64 + 0.2_real64 - 0.3_real64
end program precision_demo

The single-precision value of 0.1 is 0.100000001490116119..., the double-precision value is 0.100000000000000006.... The sum of 0.1 and 0.2 is not equal to 0.3 in double precision either; the difference is about 5.55e-17. For that reason real numbers are never compared with ==: use a tolerance, as in abs(a - b) < 1.0e-9.

$ gfortran precision.f90 -o precision
$ ./precision
real32 0.1 =   1.00000001490116119E-001
real64 0.1 =   1.00000000000000006E-001
0.1 + 0.2 == 0.3 (real64): F
0.1 + 0.2 - 0.3 =        5.55111512312578270E-017

Choosing a kind by requirements

The inquiry functions selected_int_kind(r) and selected_real_kind(p, r) return the smallest kind that can hold integers of up to r decimal digits, or reals with at least p decimal digits and an exponent range of at least r. They state the requirement and let the compiler find the kind. When no kind is available the result is -1.

selected.f90
program selected
    implicit none
    integer, parameter :: i9 = selected_int_kind(9)
    integer, parameter :: i18 = selected_int_kind(18)
    integer, parameter :: i19 = selected_int_kind(19)
    integer, parameter :: r6 = selected_real_kind(6)
    integer, parameter :: r15 = selected_real_kind(15, 300)
    integer, parameter :: r30 = selected_real_kind(30)
    integer, parameter :: r40 = selected_real_kind(40)

    print *, 'selected_int_kind(9):        ', i9
    print *, 'selected_int_kind(18):       ', i18
    print *, 'selected_int_kind(19):       ', i19
    print *, 'selected_real_kind(6):       ', r6
    print *, 'selected_real_kind(15, 300): ', r15
    print *, 'selected_real_kind(30):      ', r30
    print *, 'selected_real_kind(40):      ', r40
end program selected

Nine digits fit in kind 4, 18 digits in kind 8, and 19 digits need kind 16, a 128-bit integer that gfortran provides on this platform. A real with 6 digits is kind 4, one with 15 digits and an exponent range of 300 is kind 8, and 30 digits need the 128-bit kind 16. There is no kind with 40 digits, so the last call returns -1. The usual pattern is integer, parameter :: dp = selected_real_kind(15, 307).

$ gfortran selected.f90 -o selected
$ ./selected
 selected_int_kind(9):                   4
 selected_int_kind(18):                  8
 selected_int_kind(19):                 16
 selected_real_kind(6):                  4
 selected_real_kind(15, 300):            8
 selected_real_kind(30):                16
 selected_real_kind(40):                -1

Complex and logical values

A complex value is a pair of reals. It is written as a pair in parentheses, and the functions real and aimag return the two parts. Arithmetic, abs (the magnitude) and the other mathematical functions work on complex values directly. A logical has only two values, and the operators .and., .or., .not., .eqv. and .neqv. combine them.

complexlogical.f90
program complexlogical
    implicit none
    complex :: z
    logical :: a, b

    z = (3.0, 4.0)
    print *, 'z =', z
    print *, 'real part:', real(z), ' imaginary part:', aimag(z)
    print *, 'abs(z) =', abs(z)
    print *, 'z * z =', z * z

    a = .true.
    b = .false.
    print *, a .and. b, a .or. b, .not. a, a .eqv. b, a .neqv. b
end program complexlogical

The product of 3 + 4i with itself is -7 + 24i, and its magnitude is 5. The last line prints five logical values, shown as T and F: .true. .and. .false. is false, the .or. is true, .not. of true is false, and the last two columns show that equivalence is false and non-equivalence is true for two different values.

$ gfortran complexlogical.f90 -o complexlogical
$ ./complexlogical
 z =             (3.00000000,4.00000000)
 real part:   3.00000000      imaginary part:   4.00000000
 abs(z) =   5.00000000
 z * z =            (-7.00000000,24.0000000)
 F T F F T

Characters

A character variable has a fixed length given with len=. A shorter value is padded with blanks on the right, and a longer value is cut off. The function len returns the declared length and len_trim the length without trailing blanks. A variable declared with character(len=:), allocatable takes the length of whatever is assigned to it.

chars.f90
program chars
    implicit none
    character(len=10) :: padded
    character(len=3) :: short
    character(len=:), allocatable :: flexible

    padded = 'Fortran'
    short = 'Fortran'
    flexible = 'Fortran'

    print *, '[', padded, ']'
    print *, 'len:', len(padded), ' len_trim:', len_trim(padded)
    print *, '[', short, ']'
    print *, '[', flexible, ']'
    print *, 'len:', len(flexible)
end program chars

The variable padded has 10 characters; the seven letters are followed by three blanks, which the brackets in the output make visible, and len_trim reports 7. short has room for three characters, so only For is stored, and gfortran warns about the truncation at compile time. The allocatable variable adjusts to 7 characters.

$ gfortran -Wall chars.f90 -o chars
chars.f90:8:21:

    8 |     short = 'Fortran'
      |                     1
Warning: CHARACTER expression will be truncated in assignment (3/7) at (1) [-Wcharacter-truncation]
$ ./chars
 [Fortran   ]
 len:          10  len_trim:           7
 [For]
 [Fortran]
 len:           7

Type conversion

Arithmetic between different types converts the operand of the lower type to the higher one, in the order integer, real, complex. For two reals of different kinds, the result has the larger kind. Dividing two integers is an integer division, which truncates; one of the operands must be converted explicitly to get a fractional result. The functions int, real, nint, floor and ceiling convert real numbers to integers in different ways.

convert.f90
program convert
    use, intrinsic :: iso_fortran_env, only: real64
    implicit none
    integer :: i = 7, j = 2
    real :: r = 7.0
    real(real64) :: d = 2.0_real64

    print *, 'i / j =         ', i / j
    print *, 'real(i) / j =   ', real(i) / j
    print *, 'r / j =         ', r / j
    print *, 'kind(r + d) =   ', kind(r + d)
    print *, 'int(3.99) =     ', int(3.99), ' int(-3.99) =', int(-3.99)
    print *, 'nint(3.5) =     ', nint(3.5), ' nint(-3.5) =', nint(-3.5)
    print *, 'floor(-3.5) =   ', floor(-3.5), ' ceiling(-3.5) =', ceiling(-3.5)
end program convert

7 / 2 is 3 for integers and 3.5 as soon as one operand is real. Mixing a default real with a 64-bit real gives a result of kind 8. The conversions of -3.5 and 3.99 show the difference between the functions: int truncates toward zero, nint rounds to the nearest integer with halves away from zero, floor rounds toward minus infinity, and ceiling toward plus infinity.

$ gfortran convert.f90 -o convert
$ ./convert
 i / j =                    3
 real(i) / j =      3.50000000
 r / j =            3.50000000
 kind(r + d) =              8
 int(3.99) =                3  int(-3.99) =          -3
 nint(3.5) =                4  nint(-3.5) =          -4
 floor(-3.5) =             -4  ceiling(-3.5) =          -3

Next steps

The literals and constants article shows how to write values of a given kind, including the suffix syntax used above. For declarations and constants, see Fortran variables and declarations.

Source

GNU Fortran: the KIND intrinsic

GNU Fortran: the SELECTED_REAL_KIND intrinsic

GNU Fortran: the ISO_FORTRAN_ENV module

In this article we have looked at the five intrinsic types, the meaning of kinds, the kind constants of iso_fortran_env, the limits of integers and reals, the representation error of floating-point numbers, and type conversions. The previous article, Fortran variables and declarations, covers how to declare them, and the next one, Fortran literals and constants, covers how to write their values.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Fortran tutorials.