improved functions for floating point comparison

- less stric tolerance for comparison to zero
- better readable
- avoid "merge" on optional arguments (not safe)
- "equal" and "notEqual" are now symmetric (assignment of <= and < is
arbitrary)
This commit is contained in:
Martin Diehl 2019-03-06 15:57:42 +01:00
parent 51f8b1961f
commit a965c46025
1 changed files with 74 additions and 30 deletions

View File

@ -79,6 +79,8 @@ module prec
integer(pInt), pointer, dimension(:,:) :: p integer(pInt), pointer, dimension(:,:) :: p
end type end type
real(pReal), private, parameter :: DBL_EPSILON = 2.220446049250313E-16_pReal !< minimum positive number such that 1.0 + DBL_EPSILON /= 1.0.
real(pReal), private, parameter :: DBL_MIN = 2.2250738585072014E-308_pReal !< smallest normalized floating point number
public :: & public :: &
prec_init, & prec_init, &
@ -126,12 +128,19 @@ end subroutine prec_init
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
logical elemental pure function dEq(a,b,tol) logical elemental pure function dEq(a,b,tol)
implicit none implicit none
real(pReal), intent(in) :: a,b real(pReal), intent(in) :: a,b
real(pReal), intent(in), optional :: tol real(pReal), intent(in), optional :: tol
real(pReal), parameter :: eps = 2.220446049250313E-16 ! DBL_EPSILON in C real(pReal) :: eps
if (present(tol)) then
eps = tol
else
eps = DBL_EPSILON * maxval(abs([a,b]))
endif
dEq = merge(.True.,.False.,abs(a-b) < eps)
dEq = merge(.True.,.False.,abs(a-b) <= merge(tol,eps,present(tol))*maxval(abs([a,b])))
end function dEq end function dEq
@ -143,12 +152,19 @@ end function dEq
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
logical elemental pure function dNeq(a,b,tol) logical elemental pure function dNeq(a,b,tol)
implicit none implicit none
real(pReal), intent(in) :: a,b real(pReal), intent(in) :: a,b
real(pReal), intent(in), optional :: tol real(pReal), intent(in), optional :: tol
real(pReal), parameter :: eps = 2.220446049250313E-16 ! DBL_EPSILON in C real(pReal) :: eps
if (present(tol)) then
eps = tol
else
eps = DBL_EPSILON * maxval(abs([a,b]))
endif
dNeq = merge(.False.,.True.,abs(a-b) <= eps)
dNeq = merge(.False.,.True.,abs(a-b) <= merge(tol,eps,present(tol))*maxval(abs([a,b])))
end function dNeq end function dNeq
@ -160,12 +176,19 @@ end function dNeq
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
logical elemental pure function dEq0(a,tol) logical elemental pure function dEq0(a,tol)
implicit none implicit none
real(pReal), intent(in) :: a real(pReal), intent(in) :: a
real(pReal), intent(in), optional :: tol real(pReal), intent(in), optional :: tol
real(pReal), parameter :: eps = 2.2250738585072014E-308 ! smallest non-denormalized number real(pReal) :: eps
if (present(tol)) then
eps = tol
else
eps = DBL_MIN * 10.0_pReal
endif
dEq0 = merge(.True.,.False.,abs(a) < eps)
dEq0 = merge(.True.,.False.,abs(a) <= merge(tol,eps,present(tol)))
end function dEq0 end function dEq0
@ -177,12 +200,19 @@ end function dEq0
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
logical elemental pure function dNeq0(a,tol) logical elemental pure function dNeq0(a,tol)
implicit none implicit none
real(pReal), intent(in) :: a real(pReal), intent(in) :: a
real(pReal), intent(in), optional :: tol real(pReal), intent(in), optional :: tol
real(pReal), parameter :: eps = 2.2250738585072014E-308 ! smallest non-denormalized number real(pReal) :: eps
if (present(tol)) then
eps = tol
else
eps = DBL_MIN * 10.0_pReal
endif
dNeq0 = merge(.False.,.True.,abs(a) <= eps)
dNeq0 = merge(.False.,.True.,abs(a) <= merge(tol,eps,present(tol)))
end function dNeq0 end function dNeq0
@ -195,12 +225,19 @@ end function dNeq0
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
logical elemental pure function cEq(a,b,tol) logical elemental pure function cEq(a,b,tol)
implicit none implicit none
complex(pReal), intent(in) :: a,b complex(pReal), intent(in) :: a,b
real(pReal), intent(in), optional :: tol real(pReal), intent(in), optional :: tol
real(pReal), parameter :: eps = 2.220446049250313E-16 ! DBL_EPSILON in C real(pReal) :: eps
if (present(tol)) then
eps = tol
else
eps = DBL_EPSILON * maxval(abs([a,b]))
endif
cEq = merge(.True.,.False.,abs(a-b) < eps)
cEq = merge(.True.,.False.,abs(a-b) <= merge(tol,eps,present(tol))*maxval(abs([a,b])))
end function cEq end function cEq
@ -213,12 +250,19 @@ end function cEq
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
logical elemental pure function cNeq(a,b,tol) logical elemental pure function cNeq(a,b,tol)
implicit none implicit none
complex(pReal), intent(in) :: a,b complex(pReal), intent(in) :: a,b
real(pReal), intent(in), optional :: tol real(pReal), intent(in), optional :: tol
real(pReal), parameter :: eps = 2.220446049250313E-16 ! DBL_EPSILON in C real(pReal) :: eps
if (present(tol)) then
eps = tol
else
eps = DBL_EPSILON * maxval(abs([a,b]))
endif
cNeq = merge(.False.,.True.,abs(a-b) <= eps)
cNeq = merge(.False.,.True.,abs(a-b) <= merge(tol,eps,present(tol))*maxval(abs([a,b])))
end function cNeq end function cNeq
end module prec end module prec