我想知道在编译Fortran代码时是否存在正确的方法来将浮点数(或双数)相乘或平方,而不会出现下溢错误

gfortran -ffpe-trap=invalid,zero,overflow,underflow ...


我知道underflow选项并非总是一个好主意,但是我想知道是否可以使用此选项进行乘法运算。实际上,在下面的示例中,我知道可能发生下溢,但也许我不知道代码中的其他情况。这就是为什么我希望保留此选项的原因。

这是一个示例,其中我为矩阵的每个x,y索引计算一个向量u;组成这些向量的2个值在0和1之间。然后我计算其范数的平方。

非常合乎逻辑的是,由于该平方运算,我将导致值下溢。由于这些很小的值对我来说可以视为零。有没有一种方法可以使underflow优于使用if比较?

implicit none
double  :: u(100,100,2), uSqr(100,100)
integer :: x,y

DO x= 1, 100
    DO y = 1, 100
                CALL Poisin( u(x,y,:), x, y )
    ENDDO
ENDDO

uSqr = u(:,:,1)*u(:,:,1) + u(:,:,2) * u(:,:,2) ! where comes the underflow errors

最佳答案

您有一个答案,着眼于在某些情况下避免过度下溢的特定方法。这使用hypot函数。这部分是一个答案:如果要避免下溢,可能有一种方法可以重写算法来避免这种情况。

对于更一般的情况(例如在此问题中),希望对异常标志进行精细控制是不合适的。但是,编译器通常提供异常处理例程的接口。

一种可移植的方法是使用Fortran 2003的IEEE工具。[如果使用gfortran,则至少需要版本5.0,但是有类似的特定于编译器的方法可用。

Fortran定义了IEEE异常和标志。标志可以是安静的或发信号的。您需要的是对于下溢不是有用的诊断的部分,以不影响该计算后的下溢标志状态。

该标志称为IEEE_UNDERFLOW。我们可以使用子程序IEEE_GET_FLAG(IEEE_UNDERFLOW, value)IEEE_SET_FLAG(IEEE_UNDERFLOW, value)查询并设置其状态。如果我们期望但不关心下溢,我们也将要确保该异常不会停止。子例程IEEE_SET_HALTING_MODE(IEEE_UNDERFLOW, value)控制此模式。

因此,一个带注释的示例。

  use, intrinsic :: ieee_arithmetic, only : IEEE_SELECTED_REAL_KIND
  use, intrinsic :: ieee_exceptions

  implicit none

  ! We want an IEEE kind, but this doesn't ensure support for underflow control
  integer, parameter :: rk=IEEE_SELECTED_REAL_KIND(6, 70)

  ! State preservation/restoration
  logical should_halt, was_flagged

  real(rk) x

  ! Get the original halting mode and signal state
  call ieee_get_halting_mode(IEEE_UNDERFLOW, should_halt)
  call ieee_get_flag(IEEE_UNDERFLOW, was_flagged)

  ! Ensure we aren't going to halt on underflow
  call ieee_set_halting_mode(IEEE_UNDERFLOW, .FALSE.)

  ! The irrelevant computation
  x=TINY(x)
  x=x**2

  ! And restore our old state
  call ieee_set_halting_mode(IEEE_UNDERFLOW, should_halt)
  call ieee_set_flag(IEEE_UNDERFLOW, was_flagged)

end program

10-08 08:23