对 FORTRAN 中的种类感到困惑
Posted
技术标签:
【中文标题】对 FORTRAN 中的种类感到困惑【英文标题】:Confusion about kinds in FORTRAN 【发布时间】:2015-07-13 11:58:56 【问题描述】:两年多来,我一直在为应用物理问题的数值模拟编写 FORTRAN 代码,并尝试遵循Fortran Best Practices 中描述的约定。
更具体地说,我将参数定义为
integer, parameter:: dp=kind(0.d0)
然后将它用于我的代码中的所有双打。
但是,我发现(在这个论坛上)如果您使用其他编译器编译代码,使用 KIND 参数不一定能提供相同的精度。在this question 中,我读到一个可能的解决方案是使用 SELECTED_REAL_KIND 和 SELECTED_INT_KIND,据我所知,它们遵循一些约定。
不过,后来我发现了 ISO_FORTRAN_ENV 模块,它定义了 REAL32、REAL64 和 REAL128 KIND 参数。
我想这些确实是可移植的,而且由于它们属于 FORTRAN 2008 标准(尽管受到 GNU 支持),我想我应该使用这些吗?
因此,如果有更多知识和经验的人能解决这个困惑,我将不胜感激。
另外,我还有一个关于在 HDF5 中使用这些 KIND 的后续问题。我正在使用 H5T_NATIVE_DOUBLE 并且它确实工作正常(据我所知)但是,in this document 据说这是一个过时的功能,不应使用。相反,它们提供了一个函数
INTEGER(HID_T) FUNCTION h5kind_to_type(kind, flag) RESULT(h5_type) .
当我使用它时,打印出与 REAL64 对应的 HID_T 整数的确切数值给我 50331972,而 H5T_NATIVE_DOUBLE 给我 50331963,这是不同的。
如果我随后尝试使用由 H5kind_to_type 计算的值,HDF5 库也可以正常运行,并且使用 XDMF,我可以在 VisIt 或 Paraview 中绘制输出,而无需修改随附的 .xmf 文件。
所以我的第二个问题是(再次):这是正确的用法吗?
【问题讨论】:
我认为在 Fortran 中保证浮点变量有 8 个字节是多么麻烦,这是一个丑闻。我们真的应该在每次声明一个浮点变量时加载一个模块,或者输入一些冗长的命令吗?我陷入了与您类似的陷阱,并认为 real(8) 指定了一个 8 字节的浮点数。现在我使用 real*8,它不像 real(8) 是可移植的。它不是 Fortran 标准的一部分,但实际上每个编译器都能理解。 【参考方案1】:类型double precision
和对应的类型kind(1.d0)
由标准完美定义。但它们也不是完全固定的。事实上,历史上有很多计算机,它们的浮点数使用不同种类的原生格式,标准必须允许这样做!
所以,double precision
是一种real
,它比默认的real
具有足够高的精度。默认的real也不是固定的,一定要和电脑能用的相对应。
现在我们有了浮点数标准IEEE_754,它定义了 IEEE 单(binary32)和 IEEE 双精度(binary64)和其他一些类型。如果计算机硬件实现了这个标准,就像几乎所有 20 岁以下的计算机一样,编译器很可能会选择这两个作为real
和double precision
。
Fortran 2008 标准带来了两种常量real32
和real64
(以及其他)。它们使您能够请求具有 32 位和 64 位存储大小的真实类型。不能保证它会是 IEEE 类型,但在现代计算机上几乎可以肯定。
要请求 IEEE 类型(如果可用),请使用模块 ieee_arithmetic
中的内部函数 ieee_selected_real_kind()
。
IEEE 类型在所有计算机上都是相同的(不包括字节序!),但编译器不需要支持它们,因为您的计算机可能在硬件上不支持这些。这只是理论上的可能性,所有现代计算机都支持它们。
现在对于您的 HDF 常量,这些显然只是某个表的一些索引,它们是否不同并不重要,重要的是它们是否意味着相同,在您的情况下它们是否相同。
正如我在上面所写的,在支持 IEEE 754 的计算机上,double precision
极有可能与 IEEE double 相同。如果您使用一些改变这种行为的编译器选项,它可能不会。有一些编译器选项可以将默认 real
提升为双精度,并且还可以将 double precision
提升为四精度(128 位)以保留要求 double precision
具有更高精度和存储大小的标准语义。
结论:你可以同时使用,或者任何其他方式来选择你的种类常量(你也可以使用iso_c_binding
的c_float
和c_double
),但是你应该注意为什么这些方式不同,它们的实际含义是什么。
【讨论】:
感谢您的澄清。我将继续使用 ISO_FORTRAN_ENV 中的 REAL64 和 REAL128,因为在我看来,最好遵守 IEEE 标准。我假设硬件支持它。 据我所知,您不会为任何不支持 IEEE 754 的计算机找到任何现代 Fortran 编译器。 请注意,目前用gfortranreal128
实际上是指一种10字节的变量。使用 ifort 它具有四精度的正确含义。
gfortran 手册指出real128
使用 128 位的存储大小。
从 ISO_FORTRAN_ENV 映射到 IEEE 类型的 REALxx 常量是否是特定于处理器的。如果您想“直接请求”IEEE 单和双,那么您需要使用 IEEE 内在模块中的设施。一个处理器上的 REAL32 可能与另一个处理器上的 REAL32 不同——只要存储大小相同。以上是关于对 FORTRAN 中的种类感到困惑的主要内容,如果未能解决你的问题,请参考以下文章