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

`real_kinds` is not a constant?! If so, what is the best way to obtain the highest precision kind?

DataScientist
Valued Contributor I
1,186 Views

Why does the Intel Fortran compiler version 2021.5 not like the following code snippet,

use iso_fortran_env
integer :: i
integer, parameter :: precisions(*) = [( precision(real(0., real_kinds(i))), i = 1, size(real_kinds) )]
print *, real_kinds, size(real_kinds)
print *, (precision(real(0, real_kinds(i))), i = 1, size(real_kinds))
print *, precisions
end

Here is the error message,

/app/example.f90(5): error #6683: A kind type parameter must be a compile-time constant.   [REAL_KINDS]
print *, (precision(real(0, real_kinds(i))), i = 1, size(real_kinds))
----------------------------^

Test it here: https://godbolt.org/z/56dfobEKz

More broadly, what is the best way to obtain the real kind corresponding to the highest precision available at compile time?
What is the use of such information? Knowing this, constants can be defined only once with the highest precision and used elsewhere by coercion to the desired (lower) precision all at compile time.

 

0 Kudos
11 Replies
FortranFan
Honored Contributor II
1,139 Views

REAL_KINDS is indeed an intrinsic named constant declared in an intrinsic module.

The problem here is somewhat of a misleading error message by the Intel Fortran compiler, the issue is not that REAL_KINDS is not a named constant but that its use as shown in an array constructor does not meet the requirements of a constant expression.

Thus the code as shown does not conform and the processor detects and reports this.

Unfortunately there is no simple and straightforward facility toward "reflection" in the current standard toward what you seek.

Re: " owhat is the best way to obtain the real kind corresponding to the highest precision available at compile time?," I don't know about the best way: but a viable approach is arbitrary as show below:

   integer, parameter :: DP = selected_real_kind( p=kind(1D0) )
   integer, parameter :: HP = selected_real_kind( p=precision(1.0_dp)+1 )
   integer, parameter :: MP = merge( DP, HP, mask=(HP < 0) )
   print *, "HP = ", HP
   print *, "MP = ", MP
   print *, "max precision = ", precision( 1.0_mp )
end                                                   

where it is noted a) the standard requires a conforming processor to support what the standard defines as "double precision" kind (KIND(1D0)) toward a REAL intrinsic type and b) an inquiry is made for a REAL kind with a higher precision and if available, it's used (with KIND=mp).  Otherwise, MP defaults to the standard required "double precision" kind.

C:\temp>ifort /standard-semantics p.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.5.0 Build 20211109_000000
Copyright (C) 1985-2021 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.30.30706.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\temp>p.exe
 HP =  16
 MP =  16
 max precision =  33
FortranFan
Honored Contributor II
1,112 Views

Good catch by @mecej4 , I indeed meant the first line to be "integer, parameter :: DP = selected_real_kind( p=precision(1D0) )"

DataScientist
Valued Contributor I
1,092 Views

Thank you @FortranFan . I had something similar in mind. The only caveat is that it is not a foolproof permanent solution (although this should work for at least a number of years). I still do not understand is why the "array constructor does not meet the requirements of a constant expression". All components are compile-time constant. So a Fortran compiler should be able to compile it.

0 Kudos
IanH
Honored Contributor II
1,072 Views

The error is not being reported against an array constructor.  The array constructor is fine.  You can have array constructors, with appropriately "constant" pieces inside them, in constant expressions.  This includes array constructors with array constructor implied do loops (ac-implied-do in standard syntax terms) with appropriately constant start, stop and step bits. 

The error is being reported against an part of input output implied do loop (io-implied-do).  An io-implied-do is never considered constant - their role is to specify a sequence of items (which are not necessarily values!) for execution of input and output, which is rather different from the "sequence of values" semantics of an ac-implied-do.  Execution of an io-implied-do also changes the value of the do-variable for subsequent statements.  Bit hard to consider something with that semantics to be something "constant".

(Note that an ac-implied-do-variable (your "i") in an array constructor is a construct entity - the thing that "i" represents inside the array constructor implied do is different from the thing with the same name outside the array constructor.  This is not the case with an io-implied-do-variable. Construct entities may use definitions from surrounding scoping units to determine the type and kind of the thing inside the construct (or you can have construct local declarations, modulo compiler bugs), but they are still not the same thing as something outside the construct that relies on the same declarations.)

Consequently, the variable i inside the io-implied-do is considered, well ... a variable; a reference to a variable is ... not very constant; an array constant subscripted by a variable is also not constant; but the second, KIND argument to the REAL intrinsic must be constant.... so the compiler complains.

Try the following program.  I changed the thing being printed in the second print statement.  No more io-implied-do.

 

use iso_fortran_env
integer :: i
integer, parameter :: precisions(*) = [( precision(real(0., real_kinds(i))), i = 1, size(real_kinds) )]
print *, real_kinds, size(real_kinds)
print *, [(precision(real(0, real_kinds(i))), i = 1, size(real_kinds))]
print *, precisions
end

 

Edit to note that the compiler's subsequent output is nonsensical.... that is a compiler bug.

 

mecej4
Honored Contributor III
1,127 Views

If you use a compiler other than Intel Fortran, please make this correction to the short code given by @FortranFan, since kind() need not return the same value as precision(): change the first line of the program from

integer, parameter :: DP = selected_real_kind( p=kind(1D0) )

to

integer, parameter :: DP = selected_real_kind( p=precision(1D0) )

Without this correction, FortranFan's program gives (10, 10, 18) with Gfortran and (1, 1, 6) with NAG.

 

Steve_Lionel
Honored Contributor III
1,076 Views

In your example, the problem line does not have an array constructor. It is an IO-implied-DO loop, so the index into REAL_KINDS is not a constant.  The kind type value must be a constant. Note that line 3, which does have an array constructor, didn't trigger an error.

0 Kudos
Steve_Lionel
Honored Contributor III
1,072 Views

Another problem, which IS a compiler bug, is that the array constructor gets the wrong values. Instead of something like [6, 15, 31] it gets [6,6,6]!

I tried this variant which should do what you want:

use iso_fortran_env
integer :: i
integer, parameter :: precisions(*) = [( precision(real(0., real_kinds(i))), i = 1, size(real_kinds) )]
integer, parameter :: maxprecloc = maxloc(precisions,1)
integer, parameter :: maxpreckind = real_kinds(maxprecloc)
print *, precisions
print *, precision(real(0.,real_kinds(3)))
print *, maxpreckind, precision(real(0.,maxpreckind))
end

What I get with NAG Fortran is:

 3 6 15 31
 15
 16 31

Yes, seems there's a 16-bit real in there.  But in ifort I get:

           6           6           6
          33
           4           6

That's not right.

 

IanH
Honored Contributor II
1,070 Views

I feel sorry for the compiler though, having to do type resolution within each generated array item that results from the semantics of the array constructor.

0 Kudos
DataScientist
Valued Contributor I
1,052 Views

Thank you, Steve. I actually stumbled upon this ifort bug. What is super-confusing is the fact that this code does not compile with different compilers (e.g., gfortran, intel) for different reasons (with different error messages). So, the end-user like me inadvertently creates new coding bugs in an attempt to bypass the existing compiler bugs.

0 Kudos
DataScientist
Valued Contributor I
1,051 Views

Compiling with gfortran 11, I get the following error message,

 

 


    3 | integer, parameter :: precisions(*) = [( precision(real(0., real_kinds(i))), i = 1, size(real_kinds) )]
      |                                                            1
Error: Invalid kind for REAL at (1)

 

Is it safe to assume that Intel ifort will keep the ascending order of the kinds (in terms of precision) for the foreseeable future? In such a case, one could readily use the last kind in `real_kinds` to get the highest precision.

0 Kudos
Steve_Lionel
Honored Contributor III
994 Views

You can't assume that precisions will be in any particular order by kind.

0 Kudos
Reply