4

我想用 gfortran 编译一个程序并-O3 -ffast-math启用它,因为它可以很好地提升性能。我很困惑,gfortranisnan()捕获了一些 NaN,但不是全部。看完之后

在 C++ 中检查双精度(或浮点)是否为 NaN
如何制作可移植的 isnan/isinf 函数
Negative NaN 不是 NaN?

我的印象是,即使启用了快速数学,人们也可以通过位摆弄来检查 C 中的 NaN。然而,这让我很困惑,因为快速数学

对于依赖于数学函数的 IEEE 或 ISO 规则/规范的精确实现的程序,可能会导致不正确的输出。

根据 gcc 4.7.2 的手册页。那么,如果数字不是根据 IEEE 标准表示的,那么您怎么知道要检查哪个位呢?如果您知道它,您将如何在 Fortran 95/03/08 中实现它?

不要费心发布(x \= x)依赖于 IEEE 规则的类似解决方案。它们给出与 相同的结果isnan()。我也知道-ffpe-trap=invalid,zero,overflow,但不想停止程序。如果有帮助,我的操作系统是 64 位 LinuxMint 14。如果在 Fortran 中不可能,防水的 C 解决方案也很好。

4

3 回答 3

3

首先我要指出 gfortran 4.9 支持 IEEE_arithmetic 模块。但是,可以优化该模块中过程中的检查,并且可以应用相同的逻辑。

但是,2014 年我不能依赖 GCC 4.9,它太新鲜了。我用了以下。

当我不得不使用时,x/=x我将检查移动到一个在没有和没有链接时间优化的情况下x/=x编译的过程:-ffast-math

module my_is_nan_mod
  !poor man's replacement for the intrinsic module
  !do not use if the compiler supports the F2003 version
  !make sure not to use fast math optimizations when compiling
  use iso_fortran_env
  
  !the common extension isnan() may actually fail with fast math optimizations

  
  interface my_is_nan
    module procedure my_is_nan_real32
    module procedure my_is_nan_real64
  end interface

contains
  logical function my_is_nan_real32(x) result(res)
    real(real32), intent(in) :: x

    res = x /= x
  end function

  logical elemental function my_is_nan_real64(x) result(res)
    real(real64), intent(in) :: x

    res = x /= x
  end function

end module

它在一个单独的文件中,然后在没有 和没有 的情况下编译-Ofast--ffast-math文件-flto。请注意,缺少内联会导致严重的性能下降。

随着-ffast-math编译器看到x/=x,确定它永远不可能是真的并将表达式优化为 just .false.

于 2014-09-13T12:50:08.950 回答
3

如果有人仍在寻找答案,我发现以下适用于gfortran -O3 -Ofast -ffast-math(gfortran 版本 9.3.0):

is_nan = (.not. (x <= huge(x) .and. x >= -huge(x))) .and. (.not. abs(x) > huge(x))

事实上,我在GitHub 上发布了一些检查 Inf/NaN 的函数,这些函数旨在即使在使用激进的优化标志调用编译器时也能正常工作,例如gfortran -Ofast. GitHub 存储库中还包含一些简单的测试。

gfortran 9.3.0中ieee_is_nan包含ieee_arithmetic的内容不适用于激进的优化标志-Ofast(尽管这并不奇怪)。此外,一些编译器(gfortran 9.3.0、ifort 21.0 和 nagfor 7.0)在强制执行某些特殊编译选项时的返回类型存在错误,正如Fortran Discourseieee_is_nan上所讨论的。

为了您的方便,我复制粘贴下面的主要代码。更多细节可以在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
于 2021-09-17T03:58:01.597 回答
1

我在 gfortran-4.7 中遇到了同样的问题,并开始尝试一些表达式。对于我的测试用例,如果 x 是 NaN,则返回 true:

check = ((x*2d0==x).AND.(
         (x<-epsilon(1.d0)).OR.
         (x>+epsilon(1.d0))))

我只检查了双精度值和 -O2 -ffast-math, -O3 -ffast-math 选项。请注意,这将返回 .false。如果不使用优化标志,则必须将其与

isnan(x) .OR. check
于 2014-09-12T13:03:19.883 回答