开发者

Fortran: integer*4 vs integer(4) vs integer(kind=4)

开发者 https://www.devze.com 2023-01-06 02:01 出处:网络
I\'m trying to learn Fortran and I\'m seeing a lot of different definitions being passed around and I\'m wondering if t开发者_Go百科hey\'re trying to accomplish the same thing. What is the difference

I'm trying to learn Fortran and I'm seeing a lot of different definitions being passed around and I'm wondering if t开发者_Go百科hey'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 useing 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:


  1. The syntax shown in 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!


  1. 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.


  1. Also with Fortran 90 came the concept of default kinds, that is what you get when you don't specify a kind.

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.


  1. With Fortran 2003 and the inclusion of the intrinsic module 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.


  1. Finally, Fortran 2003 brought the 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.


  1. As a final note, I will mention the recent Fortran 2008 Standard, that extended intrinsic module iso_fortran_env to include named constants int8, int16, int32m 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号