如何在实数乘法时避免下溢?

时间:2017-04-11 17:37:44

标签: floating-point fortran underflow

我想知道在编译我的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

2 个答案:

答案 0 :(得分:3)

您有一个答案,其中介绍了在某些情况下避免过度下溢的具体方法。这使用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

答案 1 :(得分:1)

如果它只是为了避免下溢,你可能想要使用hypot或者你真的需要斜边的正方形吗?

hypot的实施应避免sqrt(x**2+y**2)的溢出/下溢问题。