In case someone is still looking for an answer, I find that the following works with gfortran -O3 -Ofast -ffast-math
(gfortran version 9.3.0):
is_nan = (.not. (x <= huge(x) .and. x >= -huge(x))) .and. (.not. abs(x) > huge(x))
Indeed, I have posted on GitHub some functions for checking Inf/NaN, which aim to work even when compilers are invoked with aggressive optimization flags, such as gfortran -Ofast
. Some simple tests are also included in the GitHub repository.
The ieee_is_nan
included in ieee_arithmetic
of gfortran 9.3.0 does not work with aggressive optimization flags like -Ofast
(although it is not surprising). In addition, some compilers (gfortran 9.3.0, ifort 21.0, and nagfor 7.0) are buggy concerning the return type of ieee_is_nan
when some special compilation options are imposed, as has been discussed here on Fortran Discourse.
For your convenience, I copy-paste the main code below. More details can be found on GitHub.
! consts.f90
module consts_mod
implicit none
private
public :: SP, DP
integer, parameter :: SP = kind(0.0)
integer, parameter :: DP = kind(0.0D0)
end module consts_mod
! infnan.f90
module infnan_mod
use consts_mod, only : SP, DP
implicit none
private
public :: is_nan, is_finite, is_inf, is_posinf, is_neginf
interface is_nan
module procedure is_nan_sp, is_nan_dp
end interface is_nan
interface is_finite
module procedure is_finite_sp, is_finite_dp
end interface is_finite
interface is_posinf
module procedure is_posinf_sp, is_posinf_dp
end interface is_posinf
interface is_neginf
module procedure is_neginf_sp, is_neginf_dp
end interface is_neginf
interface is_inf
module procedure is_inf_sp, is_inf_dp
end interface is_inf
contains
elemental pure function is_nan_sp(x) result(y)
implicit none
real(SP), intent(in) :: x
logical :: y
y = (.not. (x <= huge(x) .and. x >= -huge(x))) .and. (.not. abs(x) > huge(x))
end function is_nan_sp
elemental pure function is_nan_dp(x) result(y)
implicit none
real(DP), intent(in) :: x
logical :: y
y = (.not. (x <= huge(x) .and. x >= -huge(x))) .and. (.not. abs(x) > huge(x))
end function is_nan_dp
elemental pure function is_finite_sp(x) result(y)
implicit none
real(SP), intent(in) :: x
logical :: y
y = (x <= huge(x) .and. x >= -huge(x))
end function is_finite_sp
elemental pure function is_finite_dp(x) result(y)
implicit none
real(DP), intent(in) :: x
logical :: y
y = (x <= huge(x) .and. x >= -huge(x))
end function is_finite_dp
elemental pure function is_inf_sp(x) result(y)
implicit none
real(SP), intent(in) :: x
logical :: y
y = (abs(x) > huge(x))
end function is_inf_sp
elemental pure function is_inf_dp(x) result(y)
implicit none
real(DP), intent(in) :: x
logical :: y
y = (abs(x) > huge(x))
end function is_inf_dp
elemental pure function is_posinf_sp(x) result(y)
implicit none
real(SP), intent(in) :: x
logical :: y
y = (abs(x) > huge(x)) .and. (x > 0)
end function is_posinf_sp
elemental pure function is_posinf_dp(x) result(y)
implicit none
real(DP), intent(in) :: x
logical :: y
y = (abs(x) > huge(x)) .and. (x > 0)
end function is_posinf_dp
elemental pure function is_neginf_sp(x) result(y)
implicit none
real(SP), intent(in) :: x
logical :: y
y = (abs(x) > huge(x)) .and. (x < 0)
end function is_neginf_sp
elemental pure function is_neginf_dp(x) result(y)
implicit none
real(DP), intent(in) :: x
logical :: y
y = (abs(x) > huge(x)) .and. (x < 0)
end function is_neginf_dp
end module infnan_mod