subroutine gag_diff_char(caller,secname,secwarned,elemname,a,b)
  use gbl_message
  use gmath_interfaces, except_this=>gag_diff_char
  !---------------------------------------------------------------------
  ! @ public-generic gag_diff_elem
  ! Returns a message if the two elements a and b differ.
  ! If the elements are part of a larger section (name section), a
  ! warning about the section is also issued if not yet done.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: caller
  character(len=*), intent(in)    :: secname
  logical,          intent(inout) :: secwarned
  character(len=*), intent(in)    :: elemname
  character(len=*), intent(in)    :: a,b
  ! Local
  character(len=message_length) :: mess
  !
  if (a.eq.b)  return
  !
  if (.not.secwarned) then
    call gmath_message(seve%r,caller,secname//' sections differ')
    secwarned = .true.
  endif
  !
  write(mess,10)  elemname,a,b
  call gmath_message(seve%r,caller,mess)
  !
10 format(2X,A,T32,A,T52,A)
end subroutine gag_diff_char
!
subroutine gag_diff_inte(caller,secname,secwarned,elemname,a,b)
  use gbl_message
  use gmath_interfaces, except_this=>gag_diff_inte
  !---------------------------------------------------------------------
  ! @ public-generic gag_diff_elem
  ! Returns a message if the two elements a and b differ.
  ! If the elements are part of a larger section (name section), a
  ! warning about the section is also issued if not yet done.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: caller
  character(len=*), intent(in)    :: secname
  logical,          intent(inout) :: secwarned
  character(len=*), intent(in)    :: elemname
  integer(kind=4),  intent(in)    :: a,b
  ! Local
  character(len=message_length) :: mess
  !
  if (a.eq.b)  return
  !
  if (.not.secwarned) then
    call gmath_message(seve%r,caller,secname//' sections differ')
    secwarned = .true.
  endif
  !
  write(mess,10)  elemname,a,b
  call gmath_message(seve%r,caller,mess)
  !
10 format(2X,A,T32,I0,T52,I0)
end subroutine gag_diff_inte
!
subroutine gag_diff_long(caller,secname,secwarned,elemname,a,b)
  use gbl_message
  use gmath_interfaces, except_this=>gag_diff_long
  !---------------------------------------------------------------------
  ! @ public-generic gag_diff_elem
  ! Returns a message if the two elements a and b differ.
  ! If the elements are part of a larger section (name section), a
  ! warning about the section is also issued if not yet done.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: caller
  character(len=*), intent(in)    :: secname
  logical,          intent(inout) :: secwarned
  character(len=*), intent(in)    :: elemname
  integer(kind=8),  intent(in)    :: a,b
  ! Local
  character(len=message_length) :: mess
  !
  if (a.eq.b)  return
  !
  if (.not.secwarned) then
    call gmath_message(seve%r,caller,secname//' sections differ')
    secwarned = .true.
  endif
  !
  write(mess,10)  elemname,a,b
  call gmath_message(seve%r,caller,mess)
  !
10 format(2X,A,T32,I0,T52,I0)
end subroutine gag_diff_long
!
subroutine gag_diff_real(caller,secname,secwarned,elemname,a,b)
  use gbl_message
  use gmath_interfaces, except_this=>gag_diff_real
  !---------------------------------------------------------------------
  ! @ public-generic gag_diff_elem
  ! Returns a message if the two elements a and b differ (with some
  ! machine tolerance).
  ! If the elements are part of a larger section (name section), a
  ! warning about the section is also issued if not yet done.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: caller
  character(len=*), intent(in)    :: secname
  logical,          intent(inout) :: secwarned
  character(len=*), intent(in)    :: elemname
  real(kind=4),     intent(in)    :: a,b
  ! Local
  character(len=message_length) :: mess
  !
  if (nearly_equal(a,b,1.e-6))  return
  !
  if (.not.secwarned) then
    call gmath_message(seve%r,caller,secname//' sections differ')
    secwarned = .true.
  endif
  !
  write(mess,10)  elemname,a,b
  call gmath_message(seve%r,caller,mess)
  !
10 format(2X,A,T32,1PG12.5,T52,1PG12.5)
  !
end subroutine gag_diff_real
!
subroutine gag_diff_dble(caller,secname,secwarned,elemname,a,b)
  use gbl_message
  use gmath_interfaces, except_this=>gag_diff_dble
  !---------------------------------------------------------------------
  ! @ public-generic gag_diff_elem
  ! Returns a message if the two elements a and b differ (with some
  ! machine tolerance).
  ! If the elements are part of a larger section (name section), a
  ! warning about the section is also issued if not yet done.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: caller
  character(len=*), intent(in)    :: secname
  logical,          intent(inout) :: secwarned
  character(len=*), intent(in)    :: elemname
  real(kind=8),     intent(in)    :: a,b
  ! Local
  character(len=message_length) :: mess
  !
  if (nearly_equal(a,b,1.d-14))  return
  !
  if (.not.secwarned) then
    call gmath_message(seve%r,caller,secname//' sections differ')
    secwarned = .true.
  endif
  !
  write(mess,10)  elemname,a,b
  call gmath_message(seve%r,caller,mess)
  !
10 format(2X,A,T32,1PG19.12,T52,1PG19.12)
  !
end subroutine gag_diff_dble
!
subroutine gag_diff_datar4(caller,a,b,ndata,same)
  use gildas_def
  use gbl_message
  use gmath_interfaces
  !---------------------------------------------------------------------
  ! @ no-interface (because of argument type mismatch)
  ! Returns a message if the two flat arrays a and b differ (with some
  ! machine tolerance).
  !---------------------------------------------------------------------
  character(len=*),          intent(in)  :: caller
  integer(kind=size_length), intent(in)  :: ndata
  real(kind=4),              intent(in)  :: a(ndata),b(ndata)
  logical,                   intent(out) :: same
  ! Local
  character(len=message_length) :: mess
  real(kind=4), parameter :: eps=1.e-6
  !
  same = nearly_equal(a,b,ndata,eps)
  !
  if (.not.same) then
    write (mess,'(A,1PG7.1,A)')  'Data differ by ',eps,' relative difference at least'
    call gmath_message(seve%r,caller,mess)
  endif
  !
end subroutine gag_diff_datar4
!
function nearly_equal_r4_0d(a,b,eps)
  !---------------------------------------------------------------------
  ! @ public-generic nearly_equal
  !---------------------------------------------------------------------
  logical :: nearly_equal_r4_0d
  real(kind=4), intent(in) :: a,b
  real(kind=4), intent(in) :: eps  ! Acceptable relative difference
  ! Local
  real(kind=4) :: diff
  !
  if (a.ne.a .and. b.ne.b) then  ! Both are NaN => equal
    nearly_equal_r4_0d = .true.
    return
  endif
  !
  if (a.eq.b) then  ! Strictly equal
    nearly_equal_r4_0d = .true.
    return
  endif
  !
  diff = abs(a-b)
  if (a.eq.0. .or. b.eq.0. .or. diff.lt.tiny(a)) then
    ! a or b is zero or both are extremely close to it. Note the use
    ! of tiny() which returns the smallest floating point number
    ! representable without being a denormal number.
    ! Relative error is less meaningful here
    nearly_equal_r4_0d = diff.lt.eps*tiny(a)
    return
  endif
  !
  ! Use relative error. Note this test is commutative
  nearly_equal_r4_0d = diff/(abs(a)+abs(b)).lt.eps
  !
end function nearly_equal_r4_0d
!
function nearly_equal_r8_0d(a,b,eps)
  !---------------------------------------------------------------------
  ! @ public-generic nearly_equal
  !---------------------------------------------------------------------
  logical :: nearly_equal_r8_0d
  real(kind=8), intent(in) :: a,b
  real(kind=8), intent(in) :: eps  ! Acceptable relative difference
  ! Local
  real(kind=8) :: diff
  !
  if (a.ne.a .and. b.ne.b) then  ! Both are NaN => equal
    nearly_equal_r8_0d = .true.
    return
  endif
  !
  if (a.eq.b) then  ! Strictly equal
    nearly_equal_r8_0d = .true.
    return
  endif
  !
  diff = abs(a-b)
  if (a.eq.0. .or. b.eq.0. .or. diff.lt.tiny(a)) then
    ! a or b is zero or both are extremely close to it. Note the use
    ! of tiny() which returns the smallest floating point number
    ! representable without being a denormal number.
    ! Relative error is less meaningful here
    nearly_equal_r8_0d = diff.lt.eps*tiny(a)
    return
  endif
  !
  ! Use relative error. Note this test is commutative
  nearly_equal_r8_0d = diff/(abs(a)+abs(b)).lt.eps
  !
end function nearly_equal_r8_0d
!
function nearly_equal_r4_1d(a,b,ndata,eps)
  use gildas_def
  use gmath_dependencies_interfaces
  !---------------------------------------------------------------------
  ! @ public-generic nearly_equal
  !---------------------------------------------------------------------
  logical :: nearly_equal_r4_1d
  integer(kind=size_length), intent(in) :: ndata
  real(kind=4),              intent(in) :: a(ndata),b(ndata)
  real(kind=4),              intent(in) :: eps  ! Acceptable relative difference
  ! Local
  real(kind=4), allocatable :: diff(:)
  logical :: error
  integer(kind=4) :: ier
  integer(kind=size_length) :: idata
  !
  nearly_equal_r4_1d = .true.
  !
  do idata=1,ndata
    if (a(idata).ne.a(idata) .and. b(idata).ne.b(idata))  cycle  ! Both are NaN => equal
    if (a(idata).eq.b(idata))  cycle  ! Strictly equal
    nearly_equal_r4_1d = .false.  ! Not strictly equal, need comparison with tolerance
    exit
  enddo
  if (nearly_equal_r4_1d)  return
  !
  error = .false.
  allocate(diff(ndata),stat=ier)
  if (failed_allocate('DIFF','diff',ier,error)) return
  diff(:) = abs(a-b)
  !
  ! Can I write a vectorized form of this test?
!     if (a.eq.0. .or. b.eq.0. .or. diff.lt.tiny(a)) then
!       ! a or b is zero or both are extremely close to it. Note the use
!       ! of tiny() which returns the smallest floating point number
!       ! representable without being a denormal number.
!       ! Relative error is less meaningful here
!       nearly_equal_r4_1d = diff.lt.eps*tiny(a)
!       return
!     endif
  !
  ! Use relative error. Note this test is commutative
  nearly_equal_r4_1d = all(diff/(abs(a)+abs(b)).lt.eps)
  !
  deallocate(diff)
  !
end function nearly_equal_r4_1d
