Floating point 实数相乘时如何避免下溢?

Floating point 实数相乘时如何避免下溢?,floating-point,fortran,underflow,Floating Point,Fortran,Underflow,我想知道,当我编译我的Fortran代码时,是否有一种正确的方法可以将浮点数相乘或平方(或双倍)而不产生下溢错误,比如 gfortran -ffpe-trap=invalid,zero,overflow,underflow ... 我知道underflow选项并不总是一个好主意,但我想知道是否可以使用此选项进行乘法运算。事实上,在下面的示例中,我知道可能会发生下溢,但我可能不知道代码中的其他情况。这就是为什么我想保留这个选项,如果可能的话 这里是一个例子,我为矩阵的每个x,y指数计算一个向量u

我想知道,当我编译我的Fortran代码时,是否有一种正确的方法可以将浮点数相乘或平方(或双倍)而不产生下溢错误,比如

gfortran -ffpe-trap=invalid,zero,overflow,underflow ...
我知道
underflow
选项并不总是一个好主意,但我想知道是否可以使用此选项进行乘法运算。事实上,在下面的示例中,我知道可能会发生下溢,但我可能不知道代码中的其他情况。这就是为什么我想保留这个选项,如果可能的话

这里是一个例子,我为矩阵的每个x,y指数计算一个向量u;构成这些向量的2个值介于0和1之间。然后我计算它的范数的平方

所以非常合乎逻辑,因为这个平方运算,我会有一些值下溢。因为,对于我来说,这些非常小的值可以被认为是零。有没有一种方法比使用
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
应避免
sqrt(x**2+y**2)
的溢出/下溢问题您有一个答案,它着眼于在特定情况下避免过度下溢的具体方法。这使用了
hypot
功能。这部分是一个答案:如果你想避免下溢,可能有一种方法可以重写一个算法来避免它

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

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

Fortran定义IEEE异常和标志。旗帜可以是安静的,也可以是信号。您需要的是针对下溢不是有用诊断的零件,以便在计算后不影响下溢标志状态

该标志被称为
IEEE\u下溢
。我们可以通过子程序调用
IEEE\u GET\u FLAG(IEEE\u UNDERFLOW,value)
IEEE\u set\u FLAG(IEEE\u UNDERFLOW,value)
来查询和设置其状态。如果我们期待,但不关心,下溢,我们还希望确保异常是不间断的。子程序
IEEE\u设置\u停止\u模式(IEEE\u下溢,值)
控制此模式

下面是一个带注释的示例

  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

要明确的是,您是要避免下溢,还是要避免将下溢作为错误条件?您不能按每个文件设置
-ffpe trap
选项吗?如果是这样,您可以将上面引用的部分分离到一个源文件中,并从
-ffpe trap
列表中省略
underflow
,以编译此文件,同时保留其他源文件的原始异常陷阱列表。我假设您希望通过将
uSqr
值视为零来允许程序继续运行,尽管这些值存在下溢。我必须支持@francescalus的评论。是否要保留计算而不带错误退出?您为什么希望或需要捕获下溢的
?认真考虑不要捕获<代码>下溢< /代码>。在我看来,这是毫无用处的,甚至是有害的。@norio这就是我所知道的。但是使用这个解决方案,我不知道他们是否在这个文件中存在其他
下溢
错误。@VladimirF和@francescalus我想捕获
下溢
,以确保他们在我的其余代码中没有
下溢
错误。因此,我想知道他们是否是一个更好的方法来编写我的示例,以避免
underflow
问题。也许我的问题很愚蠢,答案是因为我做平方运算
下溢
上溢
可能会发生,所以没有其他方法,除非我使用条件测试来设置“小”和“大”值的阈值。你是对的,我一直只考虑溢出问题,但它应该以同样的方式避免下溢。感谢
斜边
技巧,但我真的需要斜边的平方。@Romain那么计算斜边的平方,问题在哪里。。。如果在这期间发生下溢,那是不可避免的。你的回答似乎很恰当。这个周末我会在家里试试,我会验证你的答案。