多重实数时如何避免下溢? [英] How to avoid underflow when multplying real numbers?

查看:264
本文介绍了多重实数时如何避免下溢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道在编译我的Fortran代码时,是否有合适的方法将乘法或方形浮点数(或双精度数)放在一起,而不会出现下溢错误:

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

我知道下溢选项并不总是一个好主意,但是我想知道是否可以用这个选项来进行乘法运算。事实上,在下面的例子中,我知道下溢可能发生,但也许我不知道我的代码中的其他情况。这是为什么我想保留这个选项,如果可能的话。

这里是一个例子,我计算一个矩阵的每个x,y指数的向量u;然后我计算它的范数的平方。

所以非常合乎逻辑,因为这个平方运算,我会有值下溢。因为这些非常小的值可以被认为是零。如果比较,有没有一种方法可以避免 underflow 比使用更好?

 隐式无
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)!哪里来的下溢错误


解决方案

在特定的情况下避免不当的下溢。这使用 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)控制着这个模式。

所以有一个注释的例子。


$ b $ pre $ lt; code> use,intrinsic :: ieee_arithmetic,仅:IEEE_SELECTED_REAL_KIND
使用,intrinsic :: ieee_exceptions

隐式无

!我们想要一个IEEE类,但是这并不能确保支持下溢控制
integer,parameter :: rk = IEEE_SELECTED_REAL_KIND(6,70)

!国家保存/恢复
逻辑should_halt,was_flagged

real(rk)x

!获取原始暂停模式和信号状态
调用ieee_get_halting_mode(IEEE_UNDERFLOW,should_halt)
调用ieee_get_flag(IEEE_UNDERFLOW,was_flagged)

!确保我们不会停止下溢
调用ieee_set_halting_mode(IEEE_UNDERFLOW,.FALSE。)

!无关计算
x = TINY(x)
x = x ** 2

!并恢复旧状态
调用ieee_set_halting_mode(IEEE_UNDERFLOW,should_halt)
调用ieee_set_flag(IEEE_UNDERFLOW,was_flagged)

结束程序
pre>

I would like to know if there is a proper way to multiply or square float (or double) numbers together without having underflow error when I compile my Fortran code like

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

I know that the underflow option is not always a good idea, but I wonder if it is possible to do multiplication with this option. In fact, in the following example I know that underflow may occur but maybe I'm not aware of other case in my codes. This is why I would like to keep this option, if possible.

Here is a example where I compute a vector u for every x,y indices of a matrix; the 2 values composing theses vectors are between 0 and 1. Then I compute the square of its norm.

So very logical, I will have values underflowing because of this square operation. Since, these very small values can be considered as zero for me. Is there a way to not underflow better than using an if comparison?

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

解决方案

You have an answer which looks at a specific way of avoiding undue underflow in certain circumstances. This uses the hypot function. This is partly an answer: if you want to avoid underflow there may be a way to rewrite an algorithm to avoid it.

For more general cases (such as in this question) where fine control of exception flags is wanted that won't be suitable. However, compilers often offer interfaces to exception-handling routines.

One portable way of doing this is using the IEEE facility of Fortran 2003. [If using gfortran you'll need at least version 5.0, but there are similar compiler-specific ways available.]

Fortran defines IEEE exceptions and flags. A flag can be quiet or signaling. What you want is for the part where underflow is not a useful diagnostic to not affect the underflow flag status after that computation.

The flag is known as IEEE_UNDERFLOW. We can query and set its status with the subroutines calls IEEE_GET_FLAG(IEEE_UNDERFLOW, value) and IEEE_SET_FLAG(IEEE_UNDERFLOW, value). If we're expecting, but don't care about, an underflow, we'll also want to ensure the exception is non-halting. The subroutine IEEE_SET_HALTING_MODE(IEEE_UNDERFLOW, value) controls this mode.

So, an annotated example.

  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

这篇关于多重实数时如何避免下溢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆