This question already has an answer here:
Using scientific notation and underscore kind specifier at the same time for real literals in Fortran
(1 answer)
Closed 1 year ago.
Does it make any difference to declare a double precision variable as
double precision :: var1, var2, var3
var1 = 1d0
var2 = 1.d0
var3 = 1.0d0
I believe var2 and var3 are identical. Are there any errors that may appear if we do not include the dot in the declaration (as in var1)?
No, there are no differences between 1d0, 1.d0 and 1.0d0 whatsoever. They represent the same literal value with the same type.
Be aware that for this specific small integer value you can get away with just using the default kind value 1.0 and you can definitely use the integer value 1.
Related
This question already has answers here:
Result of GAMMA underflows its kind
(2 answers)
Is There a Better Double-Precision Assignment in Fortran 90?
(2 answers)
Best practice when working with double precision magic numbers
(1 answer)
Closed 1 year ago.
I am using the following code to calculate cos for pi/2 in Fortran.
program precision_Fortran
IMPLICIT NONE
!!integer, parameter :: dp = kind(1.0d0) !!Gives same result as line below
integer, parameter :: dp = selected_real_kind(15, 307)
Real(dp), parameter:: pi=4.0*atan(1.0)
Real(dp) :: angle
angle = cos(pi/2.0)
write(*,*)'pi = ', pi
write(*,*)'angle = ', angle
end program precision_Fortran
I compiled using gfortran and ftn95. From both, the output is
pi = 3.1415927410125732
angle = -4.3711390001862412E-008
How do I get a better precision for angle here? For instance in C++ I see it in order of E-18, for all declaration using double.
Please let me know if more information is needed to explain it better.
Extra : The main code I am using, with physical equations having trigonometric terms, is having precision issues, and am not entirely sure, but am suspecting it's because of this. So, want to check if above could be improved somehow. Not expert with Fortran so struggling to figure this out.
This question already has an answer here:
Real value after assignment different from the real expression
(1 answer)
Closed 1 year ago.
I am seeing a strange problem, when I convert a large int to float, the values are not the same,
Here's a test program that replicates the problem
program test
integer a
a = 135000011
b = dble(a)
write(*,*) a, b
end
This prints
135000011 135000012
What is happening? How can I circumvent this?
I have found the error and how to fix this?
Since the value of b is not declared, fortran implicitly assumes its to be real, so to mitigate and correct the issue b should be declared as double precision
full program here
program test
integer a
double precision b
a = 135000011
b = dble(a)
write(*,*) a, b
end
This prints
135000011 135000011.00000
I have a large Fortran code in which most of the real variable is declared to have double precision by using
double precision
real*8
And I wonder if it is possible to force the compiler to use single-precision for those variables.
This depends on the compiler that you use. GNU Fortran supports the option -freal-8-real-4, which transforms all 8-byte reals to 4-byte ones. For instance, the following program
program p
use iso_fortran_env, only: real64
real(kind=real64) :: x
double precision :: y
real*8 :: z
print *, sizeof(x), sizeof(y), sizeof(z)
end program p
prints
8 8 8
but when compiled with -freal-8-real-4, the outputs is
4 4 4
Other compilers may have different options (or none of such kind).
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!
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
In Fortran 90 (using gfortran on Mac OS X) if I assign a value to a double-precision variable without explicitly tacking on a kind, the precision doesn't "take." What I mean is, if I run the following program:
program sample_dp
implicit none
integer, parameter :: sp = kind(1.0)
integer, parameter :: dp = kind(1.0d0)
real(sp) :: a = 0.
real(dp) :: b = 0., c = 0., d = 0.0_dp, e = 0_dp
! assign values
a = 0.12345678901234567890
b = 0.12345678901234567890
c = DBLE(0.12345678901234567890)
d = 0.12345678901234567890_dp
write(*,101) a, b, c, d
101 format(1x, 'Single precision: ', T27, F17.15, / &
1x, 'Double precisison: ', T27, F17.15, / &
1x, 'Double precision (DBLE): ', T27, F17.15, / &
1x, 'Double precision (_dp): ', T27, F17.15)
end program
I get the result:
Single precision: 0.123456791043282
Double precision: 0.123456791043282
Double precision (DBLE): 0.123456791043282
Double precision (_dp): 0.123456789012346
The single precision result starts rounding off at the 8th decimal as expected, but only the double precision variable I assigned explicitly with _dp keeps all 16 digits of precision. This seems odd, as I would expect (I'm relatively new to Fortran) that a double precision variable would automatically be double-precision. Is there a better way to assign double precision variables, or do I have to explicitly type them as above?
A real which isn't marked as double precision will be assumed to be single precision. Just because sometime later you assign it to a double precision variable, or convert it to double precision, that doesn't mean that the value will 'magically' be double precision. It doesn't look ahead to see how the value will be used.
There are several questions linking here so it is good to state some details more explicitly with examples, especially for beginners.
As stated by MRAB in his correct answer, an expression is always evaluated without any context, so
0.12345678901234567890
is a default (single) precision floating literal, no matter where does it appear. The same holds to floating point numbers in the exponential form
0.12345678901234567890E0
it is also a default precision number.
If one want to use a double precision constant, one can use D instead of E in the above form. Even if such a double precision constant is assigned to a default precision variable, it is first treated as a double precision number and then it is converted to default precision.
The way you are using in your question (employing the kind notation and several kind constants) is more general and more modern, but the principle is the same.
0.12345678901234567890_sp
is a number of kind sp and
0.12345678901234567890_dp
is a number of kind dp and it does not matter where do they appear.
As your example shows, it is not only about assignment. In the line
c = DBLE(0.12345678901234567890)
first the number 0.12345678901234567890 is default precision. Then it is converted to double precision by DBLE, but that is done after some of the digits are already lost. Then this new double precision number is assigned to c.