是否可以使用NaN设置参数变量?把它放在一个特定的模块中。我想用它来初始化其他变量。因此,如果没有更新它们,我将面临运行时错误,而不是使用一些随机数运行模拟。
为了补充Vladimir F的回答,我将提到gfortran 5.0(但不是更早的)支持IEEE固有模块。
不是real x
x=0
x=0/x
可以使用
use, intrinsic :: iso_fortran_env
use, intrinsic :: ieee_arithmetic
integer(int32) i
real(real32) x
x = ieee_value(x, ieee_quiet_nan)
i = transfer(x,i)
这给了你获得NaN值的一点灵活性。您也不必担心任何信号无效标志。[但请注意,要求ieee_signaling_nan
可能不会真正给你这个。]
注意ieee_value()
不能直接用于初始化:对它的引用不是常量表达式。对于这种使用,采用这种方法来获取位模式,并应用另一个答案的方法。
您还需要确保对每种数据类型的特性都有支持。
这是可能的。首先必须找出哪个位模式代表一个可能的NaN值。您可以将位模式存储为整数:
use, intrinsic :: iso_fortran_env
real(real64) x
integer(int64) i
x = 0
x = 0/x
print *, x
print *, transfer(x, i)
end
它给出:-2251799813685248
然后你可以使用 初始化你的变量real(real64), parameter :: nan64 = transfer(-2251799813685248_int64, 1._real64)
类似地,对于32位变量,您将得到整数-4194304,因此您可以执行
real(real32), parameter :: nan32 = transfer(-4194304_int32, 1._real32)
如果您正在使用IEEE-754兼容的浮点表示(当您关心nan时,几乎可以肯定),您也可以使用该标准中的定义。有许多可能的位模式表示非数字。指数中的所有位都等于1尾数中的一些位等于1。可以使用https://www.h-schmidt.net/FloatConverter/IEEE754.html
等转换器如果需要区分信令nan和静音nan,则静音nan尾数的第一位(最显著)为1,信令nan尾数的第一位为0。但正如https://faculty.cc.gatech.edu/~hyesoon/spr09/ieee754.pdf所指出的那样:"SNaNs",主要是出于政治原因而存在,很少使用。上面引用的转换器没有显示这种差异。
例如: use, intrinsic :: iso_fortran_env
use ieee_arithmetic
real(real32), parameter :: qnan = transfer(int(B'01111111110000000000000000000000',int32), 1._real32)
real(real32), parameter :: snan = transfer(int(B'01111111101000000000000000000000',int32), 1._real32)
if (IEEE_SUPPORT_DATATYPE(qnan)) then
print *, "qnan:", (ieee_class(qnan)==ieee_quiet_nan)
end if
if (IEEE_SUPPORT_DATATYPE(snan)) then
print *, "snan:", (ieee_class(snan)==ieee_signaling_nan)
end if
end
返回 qnan: T
snan: T
在Intel Fortran中的默认设置。在GCC (gfortran)中,默认情况下禁用信令nan。并且可以通过-fsignaling-nans
启用,但它似乎无论如何都没有帮助。
其他位,包括第一个符号位,通常被忽略。
许多编译器都有一个选项来为所有真实的变量做这个。正如francescalus所示,在fortran中它是-finit-real=nan
。手动操作可以更好地控制。
免责声明:切换到不同的平台时要小心。Endianness和其他问题可能会起作用,尽管我认为这实际上是可以的。我假设一个符合IEEE的CPU。
看,francescalus对使用标准函数的替代方案的回答。不幸的是,它不适用于parameter
常量,但很有用。
如果你的GFortran没有固有的IEEE,但有固有的iso_c_binding(就像在Windows上构建R所需的那样),下面的工作和等效于C和R NaN(在R上传递is.nan
):
real(kind = c_double), parameter :: ONE = 1_c_double
real(kind = c_double), parameter :: NAN = TRANSFER(z'7FF0000000000001', ONE)
有趣的是,real(kind = c_double), parameter :: NAN = TRANSFER(z'7FF0000000000001', 1_c_double)
没有通过is.nan
的检查。
正如francescalus在本次讨论中指出的,ieee_value
的结果不能赋值给parameter
。另一种方法是使用protected
模块变量而不是parameter
。但是,必须在程序开始时调用模型初始化函数。
module nan_module
implicit none
real, protected :: nan_real
contains
subroutine init_nan_module
use, intrinsic :: ieee_arithmetic
implicit none
nan_real = ieee_value(nan_real, ieee_quiet_nan)
end subroutine
end module nan_module
program test
use nan_module, only: init_nan_module, nan_real
implicit none
real :: x
call init_nan_module()
x = nan_real
write(*,*) x, 'isnan', isnan(x)
end program test