浮点转换导致Fortran中的算术异常

时间:2018-02-14 10:11:41

标签: fortran gfortran

以下代码传递64位浮点(double),并在将该值传递给API之前将其减少为32位。

  real*8 z
  real*4 z1
  z1 = real(z)

在某些z值上,我们得到了一个例外;

  

收到SIGFPE:发生算术异常

我使用调试器输出z中的值,结果是-1.1889755140229473e + 044,这显然是问题所在。

我认为real(z)会将此值截断为单精度,但不会出现错误。 如何将此64位双精度转换为32位单,无异常?

这是来自以前在Silverfrost Fortran 32位下编译的现有代码库,现在是64位的gfortran。将整个调用堆栈转换为单精度以解决它可能是不可能的。

2 个答案:

答案 0 :(得分:2)

作为答案发布,因为我相信我可以发现问题。

gfortran对浮点异常的行为取决于标志-ffpe-trap。虽然您没有自己设置,但可能会在您的特定平台上启用它。

使用以下程序

      real(kind=8) z
      real(kind=4) z1
      z = -1.1889755140229473d+034
      z = z*1d10
      z1 = real(z)
      write(*,*) z, z1
      end

使用

进行编译时遇到运行时异常
 gfortran -ffpe-trap=overflow -o scast scast.f90

并且程序只输出

  -1.1889755140229473E+044        -Infinity

当我省略标志-ffpe-trap=overflow时。

要真正解决您的问题,您必须决定发生溢出时该怎么做。除非您通过某种机制实际控制溢出行为, 异常的发生是一个有用的提示,即存在问题。

最后,正如伊恩布什所提到的,你应该利用当前的过渡来使用符合标准的声明。请参阅Steve Lionel的blog post,了解此问题的简短介绍。

答案 1 :(得分:1)

假设IEEE 32和64位实数,单个精度中可表示的最大模数值约为±3.40282×10 ** 38。你的数字大于此数,因此转换为单精度会引发异常。

另请注意真实的* 8和类似的不是,也从未成为Fortran的一部分。请了解Fortran类型机制。