- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content

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

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content

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

Link Copied

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content

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

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content

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?

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content

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.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content

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?

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content

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.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content

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.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content

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

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page