【问题标题】:Having parameter (constant) variable with NaN value in Fortran在 FORTRAN 中具有具有 NaN 值的参数(常量)变量
【发布时间】:2015-11-05 10:52:51
【问题描述】:

是否可以用 NaN 设置参数变量?并将其放在特定模块中。我想用它来初始化其他一些变量。因此,如果它们没有更新,我将面临运行时错误,而不是使用一些随机数运行的模拟。 我正在使用 GFORTRAN。

【问题讨论】:

  • 对于 gfortran,我很想考虑-finit-real=nan
  • -init=arrays -init=snan in ifort

标签: fortran nan gfortran


【解决方案1】:

要添加到Vladimir F's answer,我会提到 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() 不能直接用于初始化:对它的引用不是常量表达式。对于这样的使用,采用这种方法来获取位模式并应用其他答案的方法。

您还需要确保支持每种数据类型的功能。

【讨论】:

  • 没错,我仍然没有做太多,因为我必须保持与 gfortran 4.8 的兼容性。不幸的是,ieee_value 确实不允许在常量表达式中使用,所以仍然需要使用 transfer()。更多讨论在groups.google.com/forum/#!msg/comp.lang.fortran/tYC3UgAyNrY/…
  • 看来如果我想使用 NaN 进行调试并获得运行时错误,我必须使用信号 NaN 而不是安静的 (Ref)。
  • @Sorush 是的。不能保证ieee_signaling_nan 会导致这样的事情(尽管推荐)。我不知道 gfortran 返回什么 - 如果你可以测试,请告诉我。从某种意义上说,安静的 NaN 仍然很有价值:你知道出了点问题。不方便调试。
【解决方案2】:

这是可能的。您首先必须找出哪个位模式代表可能的 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)

许多编译器都可以选择为所有实变量执行此操作。正如 francescalus 所示,在 gfortran 中它是 -finit-real=nan。手动执行此操作可为您提供更好的控制。

免责声明:切换到其他平台时要小心。字节顺序和其他问题可能会起作用,尽管我认为它实际上可能没问题。我假设一个符合 IEEE 标准的 CPU。


请参阅 francescalus 对使用标准函数的替代方案的回答。不幸的是,它不适用于parameter 常量,但很有用。

【讨论】:

  • 我同意您的建议@Vladimir F,因为这样在运行时可以将变量的值更改为 NaN,反之亦然。但缺点是 NaN 的机器相关位模式。
【解决方案3】:

如果你被 GFortran 卡住了,它没有内在的 IEEE,但确实有内在的 iso_c_binding(就像在 Windows 上构建 R 所需的那样),以下工作并且等效于 C 和 R NaN(通过 @ 987654322@ R):

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 的检查。

【讨论】:

  • 你知道1_c_double 是一个整数吗?在意识到你不会再觉得失败那么有趣之后。您的第一行可以只是real(kind = c_double), parameter :: ONE = 1,它也会这样做。请参阅我的答案以了解正确的实数语法。
  • 所以最后你可以把它缩短为real(c_double), parameter :: NAN = TRANSFER(z'7FF0000000000001', 1._c_double)real(c_double), parameter :: NAN = TRANSFER(9218868437227405313_c_int64_t, 1._c_double)
  • @VladimirF,谢谢。
  • 难道 BOZ 文字只允许在数据语句和一些特定的内部操作中使用吗?
  • @RodrigoRodrigues 请参阅 (gcc.gnu.org/onlinedocs/gfortran/BOZ-literal-constants.html)。 "直到 Fortran 95,BOZ 文字只允许初始化 DATA 语句中的整数变量。由于 Fortran 2003 BOZ 文字也可以作为 REAL、DBLE、INT 和 CMPLX 的参数;结果与整数相同BOZ 文字已通过 TRANSFER 分别转换为实数、双精度、整数或复数。作为 GNU Fortran 扩展,内部过程 FLOAT、DFLOAT、COMPLEX 和 DCMPLX 的处理方式相同。"
猜你喜欢
  • 2019-09-22
  • 2016-04-09
  • 2012-07-06
  • 2018-07-20
  • 2014-06-02
  • 2013-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多