对 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 岁以下的计算机一样,编译器很可能会选择这两个作为realdouble precision

Fortran 2008 标准带来了两种常量real32real64(以及其他)。它们使您能够请求具有 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_bindingc_floatc_double),但是你应该注意为什么这些方式不同,它们的实际含义是什么。

【讨论】:

感谢您的澄清。我将继续使用 ISO_FORTRAN_ENV 中的 REAL64 和 REAL128,因为在我看来,最好遵守 IEEE 标准。我假设硬件支持它。 据我所知,您不会为任何不支持 IEEE 754 的计算机找到任何现代 Fortran 编译器。 请注意,目前用gfortran real128实际上是指一种10字节的变量。使用 ifort 它具有四精度的正确含义。 gfortran 手册指出real128 使用 128 位的存储大小。 从 ISO_FORTRAN_ENV 映射到 IEEE 类型的 REALxx 常量是否是特定于处理器的。如果您想“直接请求”IEEE 单和双,那么您需要使用 IEEE 内在模块中的设施。一个处理器上的 REAL32 可能与另一个处理器上的 REAL32 不同——只要存储大小相同。

以上是关于对 FORTRAN 中的种类感到困惑的主要内容,如果未能解决你的问题,请参考以下文章

在 Fortran 中读取 HDF5 数据集的子集时出现问题

从 Fortran 到 Linux 的退出代码

Fortran程序中令人困惑的调试错误

Matlab 与 Julia 与 Fortran 中的速度

使用 Fortran 中的内存数据调用 C 代码

在fortran中读取xls中的数据。怎么办?