I am working with a large Fortran code that uses XLF compiler for Power7
It uses these flags to set the precision to 64bit: -qrealsize=8 -qintsize=8
However a recently imported piece of code has lines similar to this:
real :: var1d(nvol)
real :: var3d(ni,nj,nk)
var1d = var3d*1.0e6
I wonder how XLF is dealing with the literal 1e6?
Main concern is; this is where a reference version and a modified version
deviate. The 9th and 10th significant figures are different for var1d.
Nastily this grows with iterations.
Data Object REALSIZE(4) in Effect REALSIZE(8) in Effect
-------------------------------------------------------------------
1.2 REAL(4) REAL(8)
1.2e0 REAL(4) REAL(8)
1.2d0 REAL(8) REAL(16)
1.2q0 REAL(16) REAL(16)
REAL REAL(4) REAL(8)
DOUBLE PRECISION REAL(8) REAL(16)
COMPLEX COMPLEX(4) COMPLEX(8)
DOUBLE COMPLEX COMPLEX(8) COMPLEX(16)
As stated in the on-line XLF manual. Thanks for all the useful suggestions. SO I will have to confirm this is not the source of discrepancy.
Related
I'm using ieee_arithmetic with Fortran on a Linux machine that runs gfortran version 5.4.0.
I'm getting an error of division by zero when trying to initialize values for Inf and NaN.
There doesn't seem to be an issue with ieee_arithmetic because elsewhere in the file I can successfully call ieee_is_finite() with no issues.
I thought that ieee_arithmetic allowed division by zero to be used for these specific cases, but I must be missing something. Below is a sample of code:
module rcrlib_gnu
use, intrinsic :: ieee_arithmetic ! requires gfortran version 5.0 or higher
implicit none
integer, parameter :: SP=kind(1.0), DP=selected_real_kind(9,99)
integer, parameter :: stderr=0
public SP, DP, is_finite, stderr, initialize
contains
subroutine initialize(infty,nan)
real(kind=DP), intent(out) :: infty, nan
infty = 1.0_dp/0.0_dp ! huge(1.0_dp)
nan = 0.0_dp/0.0_dp
end subroutine initialize
elemental function is_finite(x)
real(kind=DP), intent(in) :: x
logical :: is_finite
is_finite = ieee_is_finite(x) ! This call requires "ieee_arithmetic"
end function is_finite
end module rcrlib_gnu
It seems I'm missing something basic, so I would appreciate any help.
To reproduce the error, save the above code snippet as rcrlib_gnu_example.f90 and then execute the following line:
gfortran -o rcr rcrlib_gnu_example.f90
The resulting error output is
rcrlib_gnu_example.f90:12:18:
infty = 1.0_dp/0.0_dp ! huge(1.0_dp)
1
Error: Division by zero at (1)
rcrlib_gnu_example.f90:13:16:
nan = 0.0_dp/0.0_dp
1
Error: Division by zero at (1)
Thanks to Pascal Cuoq, I solved the problem.
The version of the initialize subroutine that compiles is below:
subroutine initialize(infty,nan)
real(kind=DP), intent(out) :: infty, nan
infty = huge(1.0_dp)+100
nan = infty-infty
end subroutine initialize
So basically set infinity to be the largest floating point number plus 100, then set NaN to be the difference between infinity and itself.
Thanks, all, for your quick responses and patience with my lack of FORTRAN experience.
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
...
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
...
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).
I am newbie to FORTRAN. I have some FORTRAN programs written in Intel FORTRAN and now I am compiling them using gfortran.
One of the subroutines uses the JFIX() function. When I complie the following error is thrown.
undefined reference to 'jfix_'
The subroutine has reference to this intrinsic function on the top like External::JFIX
Can anyone help me resolve this?
JFIX is an Intel extension to FORTRAN. It converts its argument to INTEGER(4).
There may be a GNU FORTRAN equivalent, or you may have to provide it yourself.
The Intel FORTRAN Language Reference is available from various places on the web. Here's one.
JFIX may be the one you need, but you should be careful as JFIX not only converts real to integers (as INT does), but also all other kinds of stuff to integer(4).
From the Intel Fortran Language Reference found here, it converts
INTEGER(1), INTEGER(2), INTEGER(4), INTEGER(8),
REAL(4), REAL(8), REAL(16), COMPLEX(4),
COMPLEX(8), COMPLEX(16)
to
INTEGER(4)
That was just to say to you and future readers: while it's the equivalent of INT in your case here, it is not the case everywhere.
As you're new to Fortran let me just give one more precision: the number between parenthesis is the precision kind of the variable. For instance, REAL(4) is simple precision on a "conventional" architecture, REAL(8) double precision.