I'm trying to learn Fortran and I'm seeing a lot of different definitions being passed around and I'm wondering if they're trying to accomplish the same thing. What is the difference between the following?
integer*4
integer(4)
integer(kind=4)
I'm trying to learn Fortran and I'm seeing a lot of different definitions being passed around and I'm wondering if they're trying to accomplish the same thing. What is the difference between the following?
integer*4
integer(4)
integer(kind=4)
In Fortran >=90, the best approach is use intrinsic functions to specify the precision you need -- this guarantees both portability and that you get the precision that you need. For example, to obtain integers i
and my_int
that will support at least 8 decimal digits, you could use:
integer, parameter :: RegInt_K = selected_int_kind (8)
integer (kind=RegInt_K) :: i, my_int
Having defined RegInt_K
(or whatever name you select) as a parameter
, you can use it throughout your code as a symbol. This also makes it easy to change the precision.
Requesting 8 or 9 decimal digits will typically obtain a 4-byte integer.
integer*4
is an common extension going back to old FORTRAN to specify a 4-byte integer. Although, this syntax isn't and was never standard Fortran.
integer (4)
or integer (RegInt_K)
are short for integer (kind=4)
or integer (kind=RegInt_K)
. integer (4)
is not the same as integer*4
and is non-portable -- the language standard does not specify the numeric values of kinds. Most compilers use the kind=4
for 4-byte integers -- for these compilers integer*4
and integer(4)
will provide the same integer type -- but there are exceptions, so integer(4)
is non-portable and best avoided.
The approach for reals is similar.
UPDATE: if you don't want to specify numeric types by the required precision, but instead by the storage that they will use, Fortran 2008 provides a method. reals and integers can be specified by the number of bits of storage after use
ing the ISO_FORTRAN_ENV
module, for example, for a 4-byte (32-bit) integer:
use ISO_FORTRAN_ENV
integer (int32) :: MyInt
The gfortran manual has documentation under "intrinsic modules".
Just one more explicit explanation what the kind is. The compiler has a table of different numerical types. All integer types are different kinds of the basic type -- integer
. Let's say the compiler has 1 byte, 2 byte, 4 byte, 8 byte and 16 byte integer
(or real
) kinds. In the table the compiler has an index to each of this kind -- this index is the kind number.
Many compilers choose this numbering:
kind number number of bytes
1 1
2 2
4 4
8 8
16 16
But they can choose any other numbering. One of the obvious possibilities is
kind number number of bytes
1 1
2 2
3 4
4 8
5 16
There are indeed compilers (at least g77 and NAG) which choose this approach. There are also options to change this. Therefore kind
numbers are not portable integer(kind=4)
or integer(4)
means a 4 byte integer or a 8-bytes integer depending on the compiler.
integer*4
is portable in the sense it always means 4 bytes. But on the other hand it is not portable because it has never been part of any standard. Programs using this notation are not valid Fortran 77, 90 or any other Fortran.
To see the right options how to set the kind numbers see M.S.B.'s answer.
The same concept holds for real
data types. See Fortran 90 kind parameter (the mataap's answer).
I will make reference to this enlightening article, wrote recently by @SteveLionel, and try cover some details that are not present in the other answers so far:
integer*n
or real*n
was a common extension provided by compilers long time ago, when different computer architectures started to have different designs for in-memory format of integer and real values, where n
was the size in bytes of the value stored. However, that said nothing about range or precision of those values: different implementations of a 16bit integer, for example, could provide different ranges and limit values.Register sizes could be 8, 12, 16, 30, 32, 36, 48, 60 or 64 bits, some CDC machines had ones-complement integers (allowing minus zero for an integer!), the PDP-11 line had several different floating point formats depending on the series, the IBM 360/370 had "hex normalization" for its floating point, etc [...] So popular were these extensions that many programmers thought (and even today many think) that this syntax is standard Fortran; it isn't!
When Fortran 90 came out, kind
parameters were added to the language, along with intrinsic inquiry functions (specially kind
, selected_int_kind
and selected_real_kind
, but also others, like precision
, digits
, epsilon
...) to aid the programmer to specify minimun requirements for precision and range of numeric types (still, no official mention to storage model or bytes). The syntax is integer(kind=n)
or even integer(n)
, where n
is a constant value corresponding to a kind of integer supported by the compiler. For literal constants, the syntax is 12_n
or 3.4e-2_n
.
The advantage of this solution was that Fortran didn't (and still don't) make any assumptions about the implementation details of data-types other than the results of the inquiry functions used to choose the type, so the code is parameterized by the problem being solved, not by the language or the hardware. The gotcha is, as said in other answers, each compiler can choose their kind numbers, thus assuming magic number like integer(4)
is not portable.
The default kinds were implementation dependent, though up through Fortran 2008 a compiler was required to support only one integer kind and two real kinds. (That's still true in Fortran 2018, but there's an added requirement that at least one integer kind support 18 decimal digits.) If you write a constant literal without a kind specifier, you got the default kind.
ieee_arithmetic
, you can inquire and select a real type with IEEE floating point capabilities, if avaliable.There are architectures where both IEEE and non-IEEE floating types are available, such as the HP (formerly Compaq formerly DEC) Alpha. In this case you can use IEEE_SELECTED_REAL_KIND from intrinsic module IEEE_ARITHMETIC to get an IEEE floating kind. And what if there is no supported kind that meets the requirements? In that case the intrinsics return a negative number which will (usually, depending on context) trigger a compile-time error.
iso_fortran_env
intrinsic module, that had functions to inquire the storage size of the types implemented by a compiler, with intrinsics like numeric_storage_size
and bit_size
. Another addition of Fortran 2003 revision was the iso_c_binding
intrinsic module, that provided kind parameter values to guarantee compatibility with C types, in storage, precision and range.Intrinsic module ISO_C_BINDING declares constants for Fortran types that are interoperable with C types, for example C_FLOAT and C_INT. Use these if you're declaring variables and interfaces interoperable with C.
iso_fortran_env
to include named constants int8
, int16
, int32
m int64
, real32
, real64
and real128
, whose values correspond to the kinds of integer and real kinds that occupy the stated number of bits. The gotcha is that those constants only assure storage size, not precision or range. Only use them when this is exactly what you want.In my view, this is little better than the old *n extension in that it tells you that a type fits in that many bits, but nothing else about it. As an example, there's one compiler where REAL128 is stored in 128 bits but is really the 80-bit "extended precision" real used in the old x86 floating point stack registers. If you use these you might think you're using a portable feature, but really you're not and may get bitten when the kind you get doesn't have the capabilities you need.
© 2022 - 2024 — McMap. All rights reserved.