gfortran 中的清零
Flush-to-zero in gfortran
有没有办法强制 gfortran 中的下溢清零?
我不敢相信这是第一次有人问这个问题,但我在任何地方都找不到任何内容。如果这是重复的,我认错了。
您可以使用支持 Fortran 2003 IEEE 模块的最新版本的 gfortran 来完成此操作。该标准定义了两种下溢模式——渐进和突然。 Abrupt 是您想要的,它将下溢设置为 0 并发出下溢浮点异常信号。您可以使用函数 ieee_support_underflow_control(X)
测试对控制下溢模式的支持,该函数测试下溢控制的真实 X 类型,如果支持,returns 为逻辑真。如果支持,您可以 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 文档建议在使用 IEEE 模块时随时使用编译器选项标志 -fno-unsafe-math-optimizations -frounding-math -fsignaling-nans
以确保遵守标准。
"flush to zero" 的一种懒惰方法是使用 gfortran 的 -funsafe-math-optimizations
来:
Allow math optimizations that may violate IEEE or ISO standards
或 other words:
This mode enables optimizations that allow arbitrary reassociations and transformations with no accuracy guarantees. It also does not try to preserve the sign of zeros.
例如,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
有没有办法强制 gfortran 中的下溢清零?
我不敢相信这是第一次有人问这个问题,但我在任何地方都找不到任何内容。如果这是重复的,我认错了。
您可以使用支持 Fortran 2003 IEEE 模块的最新版本的 gfortran 来完成此操作。该标准定义了两种下溢模式——渐进和突然。 Abrupt 是您想要的,它将下溢设置为 0 并发出下溢浮点异常信号。您可以使用函数 ieee_support_underflow_control(X)
测试对控制下溢模式的支持,该函数测试下溢控制的真实 X 类型,如果支持,returns 为逻辑真。如果支持,您可以 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 文档建议在使用 IEEE 模块时随时使用编译器选项标志 -fno-unsafe-math-optimizations -frounding-math -fsignaling-nans
以确保遵守标准。
"flush to zero" 的一种懒惰方法是使用 gfortran 的 -funsafe-math-optimizations
来:
Allow math optimizations that may violate IEEE or ISO standards
或 other words:
This mode enables optimizations that allow arbitrary reassociations and transformations with no accuracy guarantees. It also does not try to preserve the sign of zeros.
例如,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