【问题标题】:Flush-to-zero in gfortrangfortran中的清零
【发布时间】:2015-09-29 18:58:59
【问题描述】:

有没有办法在 gfortran 中强制将下溢刷新为零?

我不敢相信这是第一次有人问这个问题,但我在任何地方都找不到任何东西。如果这是重复的,那就过失了。

【问题讨论】:

标签: fortran gfortran underflow


【解决方案1】:

您可以使用支持 Fortran 2003 IEEE 模块的最新版本的 gfortran 来完成此操作。该标准定义了两种下溢模式——渐进式和突然式。 Abrupt 是您想要将下溢设置为 0 并发出下溢浮点异常的信号。您可以使用函数ieee_support_underflow_control(X) 测试是否支持控制下溢模式,该函数测试实际 X 类型的下溢控制,如果支持则返回逻辑真。如果支持,您可以call ieee_set_underflow_mode(.false.) 设置突然下溢模式。

下面是一个测试程序,您可以使用它来测试默认真实类型的下溢控制支持:

program test
  use, intrinsic :: ieee_arithmetic
  use, intrinsic :: iso_fortran_env, only: compiler_version, compiler_options
  implicit none
  logical :: underflow_support, gradual, underflow
  real :: fptest
  integer :: i

  print '(4a)',  'This file was compiled by ', &
       compiler_version(), ' using the options ', &
       compiler_options()
  fptest = 0.0
  underflow_support = ieee_support_underflow_control(fptest)
  if (underflow_support) then
     print *,'Underflow control supported for the default real kind'
  else
     stop 'no underflow control support'
  end if

  call ieee_set_underflow_mode(.false.)
  call ieee_get_underflow_mode(gradual)
  if (.not.gradual) then 
     print *,'Able to set abrupt underflow mode'
  else
     stop 'error setting underflow mode'
  end if

  fptest = 2e-36
  do i=1,50 ! 50 iterations max
     fptest = fptest * 0.5
     print '(e15.10)',fptest
     call ieee_get_flag(ieee_underflow,underflow)
     if (underflow) print *,'Underflow exception signaling'
     if (fptest == 0.0) exit
  end do

end program test

使用 gfortran 5.2.0 版,该程序输出:

This file was compiled by GCC version 5.2.0 using the options -mtune=generic -march=x86-64 -fno-unsafe-math-optimizations -frounding-math -fsignaling-nans
 Underflow control supported for the default real kind
 Able to set abrubpt underflow mode
.1000000036E-35
.5000000180E-36
.2500000090E-36
.1250000045E-36
.6250000225E-37
.3125000112E-37
.1562500056E-37
.0000000000E+00
 Underflow exception signaling

gfortran 5.2 文档建议使用编译器选项标志-fno-unsafe-math-optimizations -frounding-math -fsignaling-nans,以便在任何使用 IEEE 模块以确保遵守标准时使用。

【讨论】:

    【解决方案2】:

    一种“清零”的懒惰方式是使用gfortran的-funsafe-math-optimizations来:

    允许可能违反 IEEE 或 ISO 标准的数学优化

    other words:

    此模式启用优化,允许在不保证准确性的情况下进行任意重新关联和转换。它也不会尝试保留零的符号。

    例如small.f:

          program test
            real r
            r=1e-40
            print *,'r on next line'
            print *,r
          end program
    

    没有任何标志,显示一个非零的非正规(小)数字,没有错误:

    $ gfortran -g small.f
    $ ./a.out
     r on next line
       9.99994610E-41
    

    捕获非规范化的数字,在尝试打印值时崩溃:

    $ gfortran -g -ffpe-trap=denorm small.f
    $ ./a.out
     r on next line
    
    Program received signal SIGFPE: Floating-point exception - erroneous arithmetic operation.
    
    Backtrace for this error:
    #0  0x2aaaab05c26f in ???
    #1  0x2aaaaac61aed in get_float_string
            at ../../../libgfortran/io/write_float.def:1064
    #2  0x2aaaaac6423d in list_formatted_write_scalar
            at ../../../libgfortran/io/write.c:1889
    #3  0x4008f1 in test
            at /path/to/small.f:5
    #4  0x400941 in main
            at /path/to/small.f:6
    Floating point exception
    

    并添加了将其刷新为零的标志:

    $ gfortran -g -ffpe-trap=denorm -funsafe-math-optimizations small.f
    $ ./a.out
     r on next line
       0.00000000
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-09
      • 1970-01-01
      • 2011-11-06
      • 2015-10-30
      • 2011-01-06
      • 2015-03-10
      • 1970-01-01
      相关资源
      最近更新 更多