"Blackwell, Bennie F" <[log in to unmask]> asked
> I have seen (and used) the following two ways of setting machine precision.
> What is recommended way and why?
>
> method A
> INTEGER, PARAMETER :: REAL_8 = SELECTED_REAL_KIND(15,30)
> REAL(KIND=REAL_8), PARAMETER :: PI = 3.141592653589793238462643383_REAL_8
>
> method B
> INTEGER, PARAMETER :: SP = KIND(1.0) ! single precision
> INTEGER, PARAMETER :: DP = KIND(1.0D0) ! double precision
> REAL (DP), PARAMETER :: PI = 3.141592653589793238462643383_DP
In application software, I use method A, that is, I specify what kind
I need for the problem at hand, in terms of precision and range.
In library software, I make two versions using method B, and glue them
together with a generic interface.
Actually, I do it a bit differently. I write the body of the library
software once using a kind parameter specified by method A to declare local
variables, and include it within the procedure, after the declarations
of its characteristics, using an include line.
Here's an example of a quadratic root-finder module done in that way. The
body of the procedure isn't here, even though it's not obvious how to do
it in the most careful way. This isn't a discussion of numeric methods,
but rather of software engineering.
module ROOTQ_M
implicit NONE
private
public ROOTQ, SROOTQ, DROOTQ
interface ROOTQ
module procedure SROOTQ, DROOTQ
end interface
contains
subroutine SROOTQ ( COEFFS, ROOTS, ROOTSI, STATUS )
integer, parameter :: RK = kind(0.0e0)
real(rk), intent(in) :: COEFFS(0:2) ! Coeffs(i) is coefficient of x**i
real(rk), intent(out) :: ROOTSR(2) ! Real part of roots
real(rk), intent(out) :: ROOTSI(2) ! Imaginary part of roots
integer, intent(out) :: STATUS ! -1: Coeffs(1) == Coeffs(2) == 0
! 0: One root -- Coeffs(2) == 0
! 1: Two roots of opposite sign
! 2: Two real roots
! 3: Two imaginary roots
! 4: Complex conjugate roots
include 'qroot.f9h'
end subroutine SROOTQ
subroutine DROOTQ ( COEFFS, ROOTS, ROOTSI, STATUS )
integer, parameter :: RK = kind(0.0d0)
real(rk), intent(in) :: COEFFS(0:2) ! Coeffs(i) is coefficient of x**i
real(rk), intent(out) :: ROOTSR(2) ! Real part of roots
real(rk), intent(out) :: ROOTSI(2) ! Imaginary part of roots
integer, intent(out) :: STATUS ! -1: Coeffs(1) == Coeffs(2) == 0
! 0: One root -- Coeffs(2) == 0
! 1: Two roots of opposite sign
! 2: Two real roots
! 3: Two imaginary roots
! 4: Complex conjugate roots
include 'qroot.f9h'
end subroutine DROOTQ
end module ROOTQ_M
I could put the interface declarations in the include file, too, but
that just delays the inquisitive user who's searching for how to use
the procedure.
So, the user chooses what kind is needed for the application using the
SELECTED_REAL_KIND function, and calls ROOTQ. The compiler then decides
whether to use SROOTQ or DROOTQ to satisfy the user's needs. This is a
portable solution for the application developer and for the library
developer.
It would be impossible for a library provider to create a separate procedure
for each range and precision, because there would only be two (or maybe three)
kinds that result. So the generic resolution would fail. Also, it's more
work, so why try to do things the hard way?
--
Van Snyder | What fraction of Americans believe
[log in to unmask] | Wrestling is real and NASA is fake?
Any alleged opinions are my own and have not been approved or disapproved
by JPL, CalTech, NASA, Sean O'Keefe, George Bush, the Pope, or anybody else.
|