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

Constant Syntax 1.0D0 vs 1.0_dp

chauvjo
Novice
2,661 Views

In defining a double precision constant, the syntax of 1.0D0 has been used for a long time.  I have assumed that the “D0” indicates that the constant is double precision (“D”) and all decimal digits after the exponent are set to zero.   So, 1.0D0 = 1.00000000000000 and not something like 1.00000007865439.  When using the syntax 1.0_dp, do all the decimal digits after the _dp get set to zero or do you have to use the syntax 1.0D0_dp (which would seem to be redundant). 

Thanks....

0 Kudos
13 Replies
TimP
Honored Contributor III
2,661 Views

use iso_fortran_env

integer, parameter :: dp = real64

 

will certainly do the job of making 1.0_dp give you a double precision constant.

0 Kudos
Steven_L_Intel1
Employee
2,661 Views

You can use the D0 with the kind-type-parameter (_dp in your example), but if you do the D is treated the same as E and the real kind is taken from the kind parameter. Note that the kind type parameter can be any integer named constant (PARAMETER), so _dp is double precision only if you've previously defined it to be the kind that is double precision for the particular compiler.

Tim shows one way to define dp to be the kind for a 64-bit real in a portable way, but the better practice is something like this:

integer, parameter :: dp = SELECTED_REAL_KIND (15,300)

This means "pick the smallest kind with at least 15 decimal digits of precision and a range of at least 10**300. 

When you specify a kind then the literal constant is treated as that kind. 1.0 is exactly representable so indeed all the decimal fraction digits are zero. If you do something like 3.141592653589725_dp, where dp is a kind such as I showed above, then you'd get at least 15 decimal digits of precision.

The use of D0 for double precision is still standard but is not considered current best practice as what "double" means is implementation-dependent.

0 Kudos
Laura_S_3
Beginner
2,661 Views

Is there some concise document summarizing what are the current best Fortran practices? I've been using, e.g., 0.0_8 for real(8) and have been avoiding the use of "double precision" completely. But with all of the modernization that has been happening with Fortran, there seems to be a lot of things that work but but are now considered unwise.

Laura

0 Kudos
TimP
Honored Contributor III
2,661 Views

The problems with 0.0_8 are that 8 is non-portable (thus the alternatives Steve mentioned) and that assigning a parameter makes it easier to make adjustments to the source code.  Except for f2008 REAL64, these considerations go back to original f90.

0 Kudos
Steven_L_Intel1
Employee
2,661 Views

There are a number of books that teach "modern Fortran" - I list some of them here.

0 Kudos
FortranFan
Honored Contributor II
2,661 Views

Laura S. wrote:

Is there some concise document summarizing what are the current best Fortran practices? ..

@Laura S.,

See Steve's Message #6 post and especially the recommendation therein titled, "Modern Fortran - Norman Clerman and Walter Spector - Cambridge University Press, 2012, ISBN 978-0521514538".  Actually the full title of this book is "Modern Fortran: Style and Usage" and it closely addresses the "best" practices aspect.

0 Kudos
FortranFan
Honored Contributor II
2,661 Views

Steve Lionel (Intel) wrote:

.. Tim shows one way to define dp to be the kind for a 64-bit real in a portable way, but the better practice is something like this:

integer, parameter :: dp = SELECTED_REAL_KIND (15,300)

..

Steve,

Fortran standard mentions the REAL64 as simply a named constant for "64-bit real" kind, as you state above.  But do you know what the "64-bit real" itself is meant by the standard?  Is there a definition for it somewhere per Fortran standard?  Is it per some IEEE definition?  I can't seem to find it  What I'm trying to understand is whether and how a "64-bit real" can mean something different in different environments.  Thanks,

0 Kudos
Steven_L_Intel1
Employee
2,661 Views

Here's the standard's text:

9 13.8.2.21 REAL32, REAL64, and REAL128
10 1 The values of these default integer scalar named constants shall be those of the kind type parameters that specify
11 a REAL type whose storage size expressed in bits is 32, 64, and 128 respectively. If, for any of these constants,
12 the processor supports more than one kind of that size, it is processor dependent which kind value is provided. If
13 the processor supports no kind of a particular size, that constant shall be equal to -2 if the processor supports
14 kinds of a larger size and -1 otherwise.

This doesn't specify IEEE - for example, it theoretically could be VAX D for REAL64. There is a separate IEEE_ARITHMETIC intrinsic module if you specifically want an IEEE type. You could use IEEE_SELECTED_REAL_KIND (this would be my recommendation), but there are also numerous inquiry functions in the module that will tell you if particular IEEE behaviors are supported for a particular REAL kind.

0 Kudos
chauvjo
Novice
2,661 Views

Thanks Steve,

So could you summarized a general recommendation for the definition of single, double and quad precision?  Some thing like this (fortran wiki)

integer, parameter :: sp = selected_real_kind(6, 37)
integer, parameter :: dp = selected_real_kind(15, 307)  (you recommended 300, not clear on how to set the range)
integer, parameter :: qp = selected_real_kind(33, 4931)

instead of...

use, intrinsic :: iso_fortran_env
integer, parameter :: sp = REAL32
integer, parameter :: dp = REAL64
integer, parameter :: qp = REAL128

We really appreciate your help understand the details....thanks!!!

0 Kudos
Steven_L_Intel1
Employee
2,660 Views

The idea of SELECTED_REAL_KIND is to specify the precision and range your application needs. You shouldn't have to have intimate knowledge of the underlying kinds. I used 300 because that's high enough to get you IEEE double precision. Putting in 307 or 308 isn't going to change that. If your application really needs, say, only 10**100 range, then put in 100. Same for precision - do you require 15 digits or is 12 enough?

In any case, yes, I recommend using SELECTED_REAL_KIND instead of the ISO_FORTRAN_ENV constants. Of course, if you're dealing with C interoperability, then use the constants in ISO_C_BINDING.

0 Kudos
FortranFan
Honored Contributor II
2,660 Views

Steve Lionel (Intel) wrote:

.. yes, I recommend using SELECTED_REAL_KIND instead of the ISO_FORTRAN_ENV constants. ..

Perusing this thread, Steve, I'm not sure I understand your rationale for this recommendation.  Sorry for stretching out this discussion further, but can you please make one more attempt to explain your recommendation?

Over the years, I have found many coders misunderstand and misinterpret the arguments and the result from SELECTED_REAL_KIND relative to their needs that are better expressed in terms of kind references in other languages as well as the Fortran standard toward ISO_FORTRAN_ENV intrinsic module: i..e., in terms of 32-bit real, 64-bit real, etc.  Thus I feel the constants from ISO_FORTRAN_ENV are more relatable to the needs of coders and I assume that's why it got introduced into the standard starting with Fortran 2003.

So a question is this: when can REAL64 from ISO_FORTRAN_ENV be any different than SELECTED_REAL_KIND(15, 300) on any Intel architecture?  If they are always going to be the same, why not recommend ISO_FORTRAN_ENV constants as the simpler, less confusing option?

0 Kudos
Steven_L_Intel1
Employee
2,661 Views

FortranFan, with the restrictions you have made, there would be no difference. But other architectures may have different floating point formats with different characteristics.  Using the ISO_FORTRAN_ENV constants locks you in to a predetermined concept of the platform's architecture. As I wrote above, if one (theoretically) asked for SELECTED_REAL_KIND(15, 300) on a VAX system, you might get the equivalent of REAL128 because the VAX D double format has a range of 10**39 or so (but three more bits of fraction.)  There are also platforms with 60-bit REALs, etc.

And then there's the newer decimal floating formats - SELECTED_REAL_KIND now has a RADIX argument where, on some platforms (not ours), you could specify 10. That wouldn't correspond to any of the ISO_FORTRAN_ENV values.

In my view, use of the ISO_FORTRAN_ENV values is little better than writing out REAL*8. I would use these for similar purposes as the kind constants in ISO_C_BINDING when I had to interact with something non-Fortran, or when there was a requirement for a particular memory format.

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,661 Views

FortranFan,

SELECTED_REAL_KIND, from the application perspective,  is not dependent upon knowledge of the underlying support for floating point formats. Thus if your hardware supports, and compiler recognizes, REAL80 for IA32 FPU 10-byte format, then that may be a potential choice for the compiler. While REAL80 is fictitious, it is in the realm of possibility for the purposes of this discussion.

Some future architecture may support variable precision in the hardware. Note, REAL16 (16-bit) may be supported in the near future.

Jim Dempsey

0 Kudos
Reply