Compile time detection of extended-double or quad precision

Most of the above posts are using the intrinsic array real_kinds(:) to answer the question. Here is an excerpt from some of my code from about 2004. It works with algebraic expressions because the iso_fortran_env module did not exist at that time.

   integer, parameter :: COLUMBUS_WP            = selected_real_kind(14)  
   integer, parameter :: COLUMBUS_EP_REQUESTED  = selected_real_kind(17) 
   integer, parameter :: COLUMBUS_EEP_REQUESTED = selected_real_kind(30) 

   ! the following initialization expressions are equivalent to:
   !  if ( COLUMBUS_EP_REQUESTED < 0 ) then
   !     COLUMBUS_EP = COLUMBUS_WP
   !  else
   !     COLUMBUS_EP = COLUMBUS_EP_REQUESTED
   !  endif
   integer, parameter :: COLUMBUS_EP = (1+sign(1,COLUMBUS_EP_REQUESTED))/2 * COLUMBUS_EP_REQUESTED + & 
        &                              (1-sign(1,COLUMBUS_EP_REQUESTED))/2 * COLUMBUS_WP
   integer, parameter :: COLUMBUS_EEP = (1+sign(1,COLUMBUS_EEP_REQUESTED))/2 * COLUMBUS_EEP_REQUESTED + & 
        &                               (1-sign(1,COLUMBUS_EEP_REQUESTED))/2 * COLUMBUS_EP

This works as required, but of course if new real kinds are added by some compiler, then this code would need to be extended manually. The long parameter names were used intentionally so that programmers would override them with more reasonable parameter names in their codes.

There are similar algebraic expressions using merge() that can used instead. All in all, it is nice that the KIND facility in fortran allows these types of expressions to be used to define and propagate KIND values throughout a code, but I have to think that the standards committee could have made all of this much easier on programmers than they did. In the code above, I explain what it does in the comments, but wouldn’t the whole thing have been easier if programmers had been allowed to use the if-then-else in the first place?

2 Likes

Based on your idea, here’s a snippet that tests essentially all possible precisions at compile time without using iso_fortran_env:

program available_precisions

    integer, parameter :: MAXINT = 512
    integer, parameter :: ndigits(MAXINT)    = [(i,i=1,MAXINT)]
    integer, parameter :: kind_for_digits(*) = [(selected_real_kind(ndigits(i)),i=1,MAXINT)]
    integer, parameter :: max_precision      = kind_for_digits(maxval(ndigits,1,kind_for_digits>=0))
    logical, parameter :: available_kinds(*) = [(any(kind_for_digits==i),i=1,MAXINT)]
    integer, parameter :: real_kinds(*)      = pack([(i,i=1,MAXINT)],available_kinds)

    print *, 'max available precision = ',epsilon(0.0_max_precision),' kind=',max_precision
    print *, 'available real kinds    = ',real_kinds
end program available_precisions

Works on Win10+MSYS2:

 max available precision =    1.92592994438723585305597794258492732E-0034  kind=          16
 available real kinds    =            4           8          10          16```
1 Like

on mac (Version:10.14.6)
it gives the following output:

gfortran -o test_all_precisions.x test_all_precisions.f90 && ./test_all_precisions.x
 max available precision =    1.92592994438723585305597794258492732E-0034  kind=          16
 available real kinds    =            4           8          10          16

While on linux (Ubuntu 20.04.1 LTS):

gfortran -o test_all_precisions.x test_all_precisions.f90 && ./test_all_precisions.x
 max available precision =    1.92592994438723585305597794258492732E-0034  kind=          16
 available real kinds    =            4           8          10          16

All correct!!

1 Like

Not really IMHO. In your smart-as-it-is code, you actually get maximum precision available. You could also get minimum precision available (by changing maxval to minval. But you still cannot get all precisions. Yes, you get all real kinds as an array (same as real_kinds from iso_fortran_env module) but not precisions (or any other specification of a kind). Because still

  do i=1, size(real_kinds)
    precisions(i) = precision(real(1.0, kind=real_kinds(i)))
  enddo

fails to compile:

ifort version 2021.7.1:
precisions_no_iso_fortran.f90(13): error #6683: A kind type parameter must be a compile-time constant.   [REAL_KINDS]
    precisions(i) = precision(real(1.0, kind=real_kinds(i)))

gfortran-12.1.0
   13 |     precisions(i) = precision(real(1.0, kind=real_kinds(i)))
      |                                             1
Error: Invalid kind for REAL at (1)

Apparently (and unfortunately) neither ifort nor gfortran is able to use a constant (a.k.a. parameter) integer array element as a value for kind= argument to preciosion etc. Be it at compile- or run-time.

1 Like

Ask, and you shall receive…

program available_precisions

    integer, parameter :: MAXINT = 512
    integer, parameter :: ndigits(MAXINT)    = [(i,i=1,MAXINT)]
    integer, parameter :: kind_for_digits(*) = [(selected_real_kind(ndigits(i)),i=1,MAXINT)]
    integer, parameter :: max_precision      = kind_for_digits(maxval(ndigits,1,kind_for_digits>=0))
    logical, parameter :: available_kinds(*) = [(any(kind_for_digits==i),i=1,MAXINT)]
    integer, parameter :: real_kinds(*)      = pack([(i,i=1,MAXINT)],available_kinds)

    ! Max number of digits that can be achieved by the current precision
    integer, parameter :: real_precisions(*) = [(maxval(ndigits,1,kind_for_digits==real_kinds(i)),i=1,size(real_kinds))]

    print *, 'max available precision = ',epsilon(0.0_max_precision),' kind=',max_precision
    print *, 'available real kinds    = ',real_kinds
    print *, 'available precisions    = ',real_precisions

end program
1 Like

Smart indeed. Kudos! Still, the problem persists. You could get the precisions because they were used (extensively, from 1 to MAXINT) to construct the arrays. But you cannot use real_kinds(i) as a kind specification, neither in a parameter, compile-time computed definition, nor in runtime, can you?

1 Like

Thank you! I like fortran’s compact array syntax cause it’s flexible.
You’re right: even though we have a list of the available real kinds, we can use them by selection like

my_rkind = real_kinds(2)
print *, 0.0_my_rkind

but not use the real kind in a loop. That would be an attempt to a fortran “generics” feature which is unfortunately not available yet. While the above toy program only uses procedures that work with the same kind (all default integers). When I can, I try to advocate for more generics features that involve number crunching like this, because if any, that is the only future Fortran is going to have IMHO.

The standard permits that as I showed upthread with PRECISION intrinsic and implied-do over REAL_KINDS array. My sense is NAG compiler conforms to that already.

That ifort and gfortran don’t support the same is not informative here, the compilers need to be fixed and Intel Fortran will soon…

Should it work both in parameter declarations with implicit do (compile-time) and in regular do using constant array (runtime)? I’d guess only compile-time would be allowed but I might be wrong

I have written a pair of self-contained programs kinds.f90 and kinds03.f90 that may do what ivanpribec wants. They give many properties of up to 5 real kinds with different precisions and up to 6 integer kinds with different ranges available with the compiler that was used. Kinds.f90 is f95-compliant so far as I know; kinds03.f90 uses the f2003 intrinsic modules ISO_FORTRAN_ENV and IEEE_ARITHMETIC which f95 did not have. To get the programs see

https://homepages.ecs.vuw.ac.nz/~harper/fortranstuff.shtml

2 Likes

Great piece of code. For ifort it finds what I guess is a bug. Both with -assume byterecl and -assume nobyterecl options it reports file_storage_size from iso_fortran_env intrinsic module to be 8 bits while it should probably read 32 bits for -assume nobyterecl.

I’ve noticed this too about ifort. It looks like ifort is standard conforming in this respect only with the -assume byterecl option.

My kinds.f90 and kinds03.f90 have revealed a few compiler bugs over the years (at least 10) since I first wrote them. An unexpected side-effect! But compilers have revealed more bugs, which I have fixed, in the programs.

1 Like

This link seems not accessible on my side, returning a 403.

It did not work yesterday (20221118), but it works now (20221119, 0919 UTC+8).

I have similar experiences, although not limited to kind. In the past years, while working on the PRIMA project that aims to modernize some classical (F77) optimization solvers by late Professor M.J.D. Powell FRS, I have spotted a dozen of bugs in Fortran compilers, as well as two in MATLAB. Implied do loops seem to be a continuous source of bugs. gfortran has been amazingly bug-free and robust in my experience (thousands of kudos!). I look forward to testing LFortran when it is ready.

Apology to zaikunzhang for inaccessibilty of my code’s website from his/her side if it was my fault. It may not have been: msz59 managed to get the code from there. I shall email a copy of one or both programs if given an email address to send them to. You may wish to know that kinds.f90 has 331 lines, kinds03.f90 has 361 lines.

1 Like