Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28367 Discussions

Dr. Fortran recommends different kinds, but why?

DataScientist
Valued Contributor I
1,236 Views

In a great post, Dr. Fortran delves into the issue of kinds in Fortran:

https://stevelionel.com/drfortran/2017/03/27/doctor-fortran-in-it-takes-all-kinds/

At the very end of the post, Dr. Fortran recommends the use of `SELECTED_REAL_KIND` as opposed to `use iso_fortran_env, only: real64`. Why? Specifically, why did the Fortran committee stop short of requiring `SELECTED_REAL_KIND` and `use iso_fortran_env, only: real64` to behave identically?

As a separate but related question, do you, Fortran experts and enthusiasts, recommend appending literals with kind suffixes (like `_int32`) EVERYWHERE (which gets cumbersome and increases code verbosity), or is it more appropriate to use the default integer kinds everywhere in the code and set the default integer kind at the compiler level?

How do other languages like C/C++ handle kinds? I remember either FortranFan or IanH telling the story of a chemist who abandoned Fortran in favor of C just because of the way constants of default kinds are handled. (that seems like an extreme decision for a minor issue that can be solved via either the compiler or the kind suffixes, but) I understand their frustration, and I wonder why Fortran chose to not preserve the full precision of PI in the following declaration:

DOUBLE PRECISION PI
PI = 3.1415926535897



 

0 Kudos
1 Solution
IanH
Honored Contributor II
1,229 Views

SELECTED_REAL_KIND(...) and the REAL64 constant have very different criteria for how they select a kind.  How would you require them "to behave identically"?

 

SELECTED_REAL_KIND picks a kind that satisfies some minimum numerical requirements, provided by the programmer.

 

REAL64 nominates a kind that has a particular storage size.  Numerical requirements are not considered at all.

 

Given typical hardware and Fortran processors of today, there's an assumption by programmers using REAL64 that it means more or less the IEEE 64 bit floating point format, but that's not what they are asking for.  Perhaps it is unlikely, but there is the possibility they might get a rude surprise with typical hardware and Fortran processors of some tomorrow.

 

(If you really want the IEEE 64 bit floating point format - see IEEE_SELECTED_REAL_KIND.)

 

When choosing a method of nominating a kind, use the method that is best aligned for what you actually want.  If you are doing non-trivial calculations in your program, that's probably something tied to numerical properties.

 

As for the separate-but-related question, with some separate-but-related thoughts:

  • Do not plan on relying on compiler switches.  Write the code to mean what it should mean.
  • Do not sprinkle magic numbers through out your code.  Magic numbers should be represented by named constants, hence they only get defined in the one place and verbosity is .  Note though - I don't consider simple, low range integer values in expressions to be magic - and the requirements on default integer and the nature of kind promotion are such that with something like `y = 2 * x` (with y and x real) is not going to be problematic.

(This magic number thing is the primary reason in my  mind that the historical non-standard REAL*8 syntax just had to go, and should never come back.)

  • Names used for kind parameters should reflect the requirements and context for their use, not their definitions.  I've sometimes seen something like:

 

INTEGER, PARAMETER :: sp = KIND(1.0)
REAL(sp) :: x
REAL(sp) :: y
...

 

and then later on someone decides that we need more precision - so they change the opening line to read

 

INTEGER, PARAMETER :: sp = KIND(1.0D0)

 

and... wtf?  Consider your use of int32 as a kind name scattered throughout code in that regard (one day int32 ends up meaning a 64 bit integer!).

  • Simple integers in real expressions aside, be explicit in situations where kind conversion may happen. 

 

(The behaviour of the rich text control in this forum has become infuriating.)

View solution in original post

7 Replies
IanH
Honored Contributor II
1,230 Views

SELECTED_REAL_KIND(...) and the REAL64 constant have very different criteria for how they select a kind.  How would you require them "to behave identically"?

 

SELECTED_REAL_KIND picks a kind that satisfies some minimum numerical requirements, provided by the programmer.

 

REAL64 nominates a kind that has a particular storage size.  Numerical requirements are not considered at all.

 

Given typical hardware and Fortran processors of today, there's an assumption by programmers using REAL64 that it means more or less the IEEE 64 bit floating point format, but that's not what they are asking for.  Perhaps it is unlikely, but there is the possibility they might get a rude surprise with typical hardware and Fortran processors of some tomorrow.

 

(If you really want the IEEE 64 bit floating point format - see IEEE_SELECTED_REAL_KIND.)

 

When choosing a method of nominating a kind, use the method that is best aligned for what you actually want.  If you are doing non-trivial calculations in your program, that's probably something tied to numerical properties.

 

As for the separate-but-related question, with some separate-but-related thoughts:

  • Do not plan on relying on compiler switches.  Write the code to mean what it should mean.
  • Do not sprinkle magic numbers through out your code.  Magic numbers should be represented by named constants, hence they only get defined in the one place and verbosity is .  Note though - I don't consider simple, low range integer values in expressions to be magic - and the requirements on default integer and the nature of kind promotion are such that with something like `y = 2 * x` (with y and x real) is not going to be problematic.

(This magic number thing is the primary reason in my  mind that the historical non-standard REAL*8 syntax just had to go, and should never come back.)

  • Names used for kind parameters should reflect the requirements and context for their use, not their definitions.  I've sometimes seen something like:

 

INTEGER, PARAMETER :: sp = KIND(1.0)
REAL(sp) :: x
REAL(sp) :: y
...

 

and then later on someone decides that we need more precision - so they change the opening line to read

 

INTEGER, PARAMETER :: sp = KIND(1.0D0)

 

and... wtf?  Consider your use of int32 as a kind name scattered throughout code in that regard (one day int32 ends up meaning a 64 bit integer!).

  • Simple integers in real expressions aside, be explicit in situations where kind conversion may happen. 

 

(The behaviour of the rich text control in this forum has become infuriating.)

DataScientist
Valued Contributor I
1,224 Views

thanks for the nice answer, @IanH . I assume then, that even the performance one gets with `SELECTED_REAL_KIND ` and `REAL64` may not be the same either, now or in the future, because each one may require a different size of data. Am I right?

0 Kudos
Steve_Lionel
Honored Contributor III
1,219 Views

I explain exactly why I recommend SELECTED_REAL_KIND in my post. @IanH has it right - the constants such as REAL64 tell you nothing except storage size. If you want to specify something like "double precision" because you need more significant digits, then you should use SELECTED_REAL_KIND to say how much precision (and/or range) you want.

Performance isn't really the point here - it's not making unwarranted assumptions.

And, yes, I hate the new text editor here, along with the forum telling me there are new replies until I read them twice.

DataScientist
Valued Contributor I
1,216 Views

Thanks @Steve_Lionel . But if it is all about size, wouldn't it suffice to represent only sizes in ISO_FORTRAN_ENV? That is, why is there a need to have both INT32 and REAL32, instead of having for example SIZE32 to represent both, if that is all about the size of the type?

0 Kudos
Steve_Lionel
Honored Contributor III
1,212 Views

That the kind values in Intel Fortran correspond to storage sizes is just an implementation choice. Some compilers number their kinds 1,2,3, etc. There is also no standard relationship between the size of an integer and a real that have the same kind value. You cannot assume that an INTEGER(4) and a REAL(4) take the same space - so if that's what you want, then INT32 and REAL32 could be useful, assuming you didn't care about any other properties.

 

One could have integer kinds 37, 428 and 65535, real kinds of 3, 17 and 42. You'd need to use the inquiry functions to determine their properties. And, as also noted, if you specifically want IEEE reals, you should use IEEE_SELECTED_REAL_KIND. I know of platforms that support both IEEE and non-IEEE floats.

Arjen_Markus
Honored Contributor I
1,139 Views

Indeed, in a distant past I worked on a Convex computer and that had two different floating-point formats, one IEEE-compatible (not sure about the exct details) and one that was described as the native and faster kind. They took the same storage, the only difference seems to have been the exponent - identical bit patterns gave a value that was different by a factor four.

Well, this was before the wide sreapding of Fortran 90 compilers and you had to use a compiler option to select either one (and of course be careful not to mix up object files compiled with different options!). With modern Fortran's kinds you can easily distinguish them, even though selected_real_kind does not really help here - the range and precision would have been almost the same. 

jimdempseyatthecove
Honored Contributor III
1,122 Views

In recent history (for us old time Fortran programmers) IVF added IEEE Quad Precision (aka REAL(16)). For those few programs using SELECTED_REAL_KIND with overly large precision and/or dynamic range, the newer (supporting REAL(16)) compiler would have changed the internal representation (and binary file format) from REAL(8) to REAL(16)...

As to if you got what you wanted is subject to discussion. IOW "you get what you asked for" is not necessarily "you get what you wanted" (and what you want is subject to change depending upon what you end up getting).

Jim Dempsey

Reply