Confusing double precision real in Fortran - fortran

Have this burning question on my mind right now: What is the "accepted" way to declare double precision real in modern Fortran? In order from oldest to newest, the story seems to go like this: DOUBLE PRECISION, then REAL(kind=8), then INTEGER, PARAMETER :: dp=kind(1.d0) with REAL(kind=dp)--Metcalf now says dp=kind(0.d0)--and now float32=selected_real_kind(6,37) or float64=selected_real_kind(15,307). So...
How should I be declaring double precision real now?
Is kind redundant in REAL(kind=dp)?
Are there any special flags needed at compile time to invoke double precision real with gfortran or ifort?

Personally I now write
use, intrinsic :: iso_fortran_env
which includes parameters such as int32,real64 which have the obvious meanings, and can be used like this:
real(real64) :: a_64_bit_real_scalar
Note that kind=8 is not guaranteed, by the standard, to deliver an 8-byte kind. The values that kind parameters take are not standardised and do vary from compiler to compiler.
You could, if you want, write statements such as
use, intrinsic :: iso_fortran_env, dp=>real64
...
real(dp) :: a_64_bit_real_scalar

1)How should I be declaring double precision real now?
I personally prefer using the
integer, parameter :: wp = selected_real_kind(15,307)
real(wp) :: var
method for this. But as Mark points out, the iso_fortran_env is another straight-forward method. If you plan on using interfaces to C, you may want to try the ISO_C_BINDING module and use
use iso_c_binding
real(c_double) :: var
And get the double precision you want.
2) Is kind redundant in REAL(kind=dp)?
Yes it is.
3) Are there any special flags needed at compile time to invoke double precision real with gfortran or ifort?
For gfortran you can use the compilation flag -fdefault-real-8. For ifort, you can use the -real-size=64 flag.

The current recommended way of declaring double precision reals in Fortran is:
INTEGER, PARAMETER :: rk = SELECTED_REAL_KIND(15, 307)
REAL(rk) :: x
...

Related

How to read in single precision numbers into fortran as double precision?

I have a data file, some of the numbers are really big, like 1E252. How do I read data into Fortran as 1D252. I've tried declaring the variable as double and kind=16, but when its read in as 1E252, it errors.
Unfortunately, the easy solution, to parse the data file and convert all Es to Ds won't work because it also needs to be compatible with python.
Is there something more elegant than this?
program test
Integer :: i
real (kind = 8) :: another_test
Character(len=20) :: char_arr
char_arr = "1.10E+223"
Do i = 1,20
If (char_arr(i:i) == "E") then
char_arr(i:i) = "D"
EndIf
EndDo
Read(char_arr, *) another_test
Write(*,*) another_test
end program test
This isn't a full answer, mainly because I haven't been able to reproduce your premise. (I'm at my home computer, I only have access to gfortran v7.3.0 on Windows 10/cygwin.)
This code compiled perfectly fine and printed the correct value:
program large_float
use iso_fortran_env, only: real64
implicit none
character(len=20) :: strrep
real(kind=real64) :: val
strrep = '1.10E+223'
read (strrep, *) val
print *, val
end program large_float
Now you can see what I do differently to you is this: Instead of the ambiguous kind=8 I use the intrinsic iso_fortran_env to get the correct kind for 64 bit floating values.
I would strongly recommend to use this syntax, as it is compiler independent1 and you will know exactly what you get.
1iso_fotran_env was added I think in Fortran 2003, but I don't know of any Fortran compiler that doesn't recognise it. If you get an error, you can still use the selected_real_kind:
integer, parameter :: real64 = selected_real_kind(R=300)

Is there a short, portable way to specify "kind" in Fortran?

I generally use this form to get double precision in my Fortran code:
use, intrinsic :: ISO_FORTRAN_ENV
real(kind=real64) :: a = 5d0
However, when defining several variables in a row, real(kind=real64) gets very repetitive. It's tempting to just use real*8, although I've avoided doing so because I've been taught that, although unlikely, it has the potential to make the program non-portable.
From another question I found on the subject I see that real(real64) works, but I don't know if this is good practice; it seems to be the same as using real(8) since, at least on my system, real64 = 8. Is there a shorter way than real(kind=real64) to specify a kind in a variable declaration? Is there even a realistic chance of real*8 causing problems?
The difference between
use, intrinsic :: ISO_FORTRAN_ENV
Real( kind = real64 ) :: a
and
use, intrinsic :: ISO_FORTRAN_ENV
Real( real64 ) :: a
is purely stylistic. Both are equally portable, and are identical as far as the code is concerned. In fact I am having problems understanding why you think they are different. If you think real64 is too long to type you can always use
use, intrinsic :: ISO_FORTRAN_ENV
Integer, Parameter :: wp = real64
Real( wp ) :: a
What is not technically portable is using 5d0 as a constant and assuming it is a real with the same kind as real64. Double precision is obsolete, forget it, rather use the kind mechanism properly with
use, intrinsic :: ISO_FORTRAN_ENV
Integer, Parameter :: wp = real64
Real( wp ) :: a = 5.0_wp

Quadruple precision for abs and sign

I am trying to change the precision of the abs and sign with gfortran (gcc version 5.3.1 and x86_64-linux-gnu).
I know I can change to dabs and dsign to have double precision but what about quad precision, is it possible?
For sqrt(x) for instance, I simply change to x**(0.5q0) with the arg defined as a real(16). I read that some compilers do not have the intrinsic routines implemented in quad or extended precision, see e.g. here.
If gfortran has been compiled with support for libquadmath (on Linux it typically is), then it supports this right away. All you need to do is declare your variables and literals quadruple precision, and use the generic versions abs and sign.
However, using real(16) is not portable (and outdated). Better use something standardized such as selected_real_kind(p=30).
Here is a short example to illustrate this:
program test
integer, parameter :: qp = selected_real_kind(p=30)
real(qp) :: a
a = -2._qp
print *, abs(a)
print *, sqrt(-a)
end program
The output is:
2.00000000000000000000000000000000000
1.41421356237309504880168872420969818
Compare this to the result of Wolfram alpha:
1.414213562373095048801688724209698078569671875376948073176
Or...
https://software.intel.com/en-us/node/525335
PROGRAM!SUBROUTINE!FUNCTION
USE ISO_C_BINDING
IMPLICIT NONE
REAL(KIND=C_LONG_DOUBLE) :: A
!or maybe...
REAL(C_LONG_DOUBLE) :: B
...

Calling function with configurable real precision

The goal:
Have a function work with configurable working precision.
When I try this:
program vierkantsvergelijking
implicit none
integer, parameter :: dp = kind(0.d0)
integer, parameter :: sp = kind(0.0)
print *, algoritme1(-5771.,2.,dp)
contains
function algoritme1(b,c,wp) result( solution)
integer :: wp ! working precision
real(kind=wp) :: b,c,D
real(kind=wp), dimension(2) :: solution
D = sqrt((b/2)**2 - c)
solution(1) = -b/2 + D
solution(2) = -b/2 - D
end function algoritme1
end program
I get:
Error: Type mismatch in argument 'b' at (1); passed REAL(4) to UNKNOWN
Why is this not working and how can I achieve my goal?
Yes, or rather no, that's not going to work, not no how. The Intel Fortran compiler complains, about this line:
real(kind=wp) :: b,c,D
that
A kind type parameter must be a compile-time constant. [WP]
It makes the same complaint about real(kind=wp), dimension(2) :: solution too. This is a deep-rooted feature of Fortran.
To do what you want you will have to define a generic interface, along these lines
interface algoritme1
procedure :: algoritme1_sp, algoritme1_dp
end interface
and write the code for both those procedures. The compiler can then determine which one is called by the function signature; presumably one would have sp arguments, the other dp arguments.
You might think that this all means that Fortran doesn't do generic procedures, I'll leave that question to the sophists and language nit-pickers. It would be worth your while to search around for generic programming in Fortran; even here on SO there are tricks and tips on how to better avoid writing multiple implementations of what the programmer believes (at odds with the compiler) to be the 'same' code.

How to automatically convert a Fortran90 program whose variables are in double precision into real?

everyone
I have a Fortran90 program, and the variables are in double precision or complex*16, now I have to write another program whose variables are in real or complex, and all other things are the same as the original program.
The straightforward way is to rewrite every declaration, but I'm wondering if there are other simpler ways to achieve this, I'm using gfortran as the compiler.
Thanks
Probably the cleanest (althoug not the easiest) way would be to rewrite your program to have adjustable precision for the variables:
program test
implicit none
integer, parameter :: rp = kind(1.0d0)
real(rp) :: myreal
complex(rp) :: mycomplex
By setting the parameter rp (real precision) to kind(1.0) instead of kind(1.0d0) you can switch from double to single. Alternatively, with fortran 2003 compatible compilers you can also use the names real64 and real32 after invoking the iso_fortan_env module. (UPDATE: it needs a fortran 2008 compatible compiler, not fortran 2003, see the comment of IanH).