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?