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