Josué Lopes
Josué Lopes

Reputation: 33

Defining Exponent in Fortran

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

Answers (1)

Ross
Ross

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

Related Questions