I’m doing some digging and this is confusing me even further:
module kinds
implicit none
!> Single precision real numbers, 6 digits, range 10⁻³⁷ to 10³⁷-1; 32 bits
integer, parameter :: sp = selected_real_kind(6, 37)
!> Double precision real numbers, 15 digits, range 10⁻³⁰⁷ to 10³⁰⁷-1; 64 bits
integer, parameter :: dp = selected_real_kind(15, 307)
!> Quadruple precision real numbers, 33 digits, range 10⁻⁴⁹³¹ to 10⁴⁹³¹-1; 128 bits
integer, parameter :: qp = selected_real_kind(33, 4931)
!> Char length for integers, range -2⁷ to 2⁷-1; 8 bits
integer, parameter :: i1 = selected_int_kind(2)
!> Short length for integers, range -2¹⁵ to 2¹⁵-1; 16 bits
integer, parameter :: i2 = selected_int_kind(4)
!> Length of default integers, range -2³¹ to 2³¹-1; 32 bits
integer, parameter :: i4 = selected_int_kind(9)
!> Long length for integers, range -2⁶³ to 2⁶³-1; 64 bits
integer, parameter :: i8 = selected_int_kind(18)
integer, parameter :: wp = dp
end module kinds
program test_kinds
use kinds
implicit none
real(dp) :: x
real(dp) :: y1, y2, y3, y4, y5, y6, y7, y8, y9, y10
x = 0.5_dp
! y1 shows a loss of precision
y1 = (2 * x**5) ** (1.0 / 3.0) + 3*exp(x*2)
y2 = (2 * x**5) ** (1.0_dp / 3.0_dp) + 3*exp(x*2)
y3 = (2.0_dp * x**5.0_dp) ** (1.0_dp/3.0_dp) + 3.0_dp*exp(x*2.0_dp)
! y4, y5 and y6 give me the same values
y4 = 1 + y3
y5 = 1.0 + y3
y6 = 1.0_dp + y3
! y7 and y8 also give me the same values
y7 = 0.5 + y3
y8 = 0.5_dp + y3
! y9 loses some digits
y9 = 0.325 + y3
y10 = 0.325_dp + y3
write(*,*) 'y1 = ', y1
write(*,*) 'y2 = ', y2
write(*,*) 'y3 = ', y3
write(*,*) 'y4 = ', y4
write(*,*) 'y5 = ', y5
write(*,*) 'y6 = ', y6
write(*,*) 'y7 = ', y7
write(*,*) 'y8 = ', y8
write(*,*) 'y9 = ', y9
write(*,*) 'y10 = ', y10
end program
In this example, the compiler (gfortran 14.2.1) has issues with the (1.0 / 3.0) division at y1. But it seems unnecessary to specify _dp
to the rest of the numbers in the formula (in summary, y2 gives me the same result as y3).
So I’ve tried some random tests. summing 1
, 1.0
or 1.0_dp
gives me the same result up until the 16th decimal. Summing 0.5
or 0.5_dp
also gives me the same result. However, summing up a broken real such as 0.325
doesn’t give me the same result as 0.325_dp
.
I’m probably going to add _dp
to anything just in case, but is there any logic to the kind conversions?