Reputation: 33
I've been having some trouble with variables precision in my code...
For a while i've been declaring variables as real(kind=8) :: var
and I now understand that this is not very portable and has some other complications, but basically I'm getting a lot of imprecision in numerical calculations.
Now I'm using:
INTEGER, PARAMETER :: R8 = SELECTED_REAL_KIND (30, 300)
with variable declaration: real(R8) :: var1,var2.
Before I usually initialized variables as var1 = 1.0D0
and now I'm using var1 = 1.0_R8
but what should I do with var1 = 1.0D-20
? I've run a simple code which proved that 1.0D-20
won't give me an accurate result but something like 10.0_r8**(-20.0_r8)
will. Is there an easier way to define the variable? I know that 1D-20
is very small but the code I'm using really needs 30 decimal case precision.
Thank you for your help!
Upvotes: 3
Views: 3207
Reputation: 2169
There's really two things happening here. First, declaring an exponent using d
notation is the same as declaring it as type double precision
.
Second, the r8
variable you declare requires more precision than most (all?) 8-byte representations. So you're actually declaring most of your variables as quad, then initializing them as double, which is the source of your problem.
As mentioned in the comments, the answer to your explicit question is to declare exponents using the following notation
real(mytype) :: a = 1.23e-20_mytype
This notation is cumbersome but easy to get used to for constant declaration.
Here's a little sample code I used to test your types:
program main
use ISO_FORTRAN_ENV, only : REAL64 => REAL64, REAL128
implicit none
INTEGER, PARAMETER :: R8 = SELECTED_REAL_KIND (30, 300)
real(r8) :: x, y, z
real(REAL64) :: a, b, c
x = 1.23d-20
y = 1.23e-20_r8
z = 1.23_r8*(10._r8**-20)
write(*,*) x
write(*,*) y
write(*,*) z
a = 1.23d-20
b = 1.23e-20_REAL64
c = 1.23_REAL64*(10._REAL64**-20)
write(*,*) a
write(*,*) b
write(*,*) c
write(*,*) 'Types: ', REAL64, R8, REAL128
end program main
for Intel 16.0, this gives:
mach5% ifort main.f90 && ./a.out
1.230000000000000057423043720037598E-0020
1.230000000000000000000000000000000E-0020
1.230000000000000000000000000000002E-0020
1.230000000000000E-020
1.230000000000000E-020
1.230000000000000E-020
Types: 8 16 16
Upvotes: 3