【问题标题】:Fortran 90 kind parameterFortran 90 种参数
【发布时间】:2010-10-24 17:03:09
【问题描述】:

我无法理解 Fortran 90 的 kind 参数。据我所知,它不能确定变量的精度(即浮点数或双精度),也不能确定变量的类型。

那么,它决定什么,它到底是干什么用的?

【问题讨论】:

  • 你指的是种类符号吗?

标签: fortran


【解决方案1】:

总结其他答案:kind 参数指定内在数据类型(例如整数和实数)的存储大小(因此间接地指定精度)。

但是,现在推荐的方法是不要在源代码中指定变量的种类值,而是使用编译器选项来指定我们想要的精度。例如,我们在代码中写入:real :: abc,然后使用编译选项-fdefault-real-8(对于 gfortran)指定一个 8 字节浮点数来编译代码。对于ifort,对应的选项是-r8

更新:

这里的 Fortran 专家似乎强烈反对上述推荐的方式。尽管如此,我仍然认为上述方法是一种很好的做法,有助于减少在 Fortran 代码中引入错误的机会,因为它保证您在整个程序中使用相同的 kind-value(您确实需要使用不同的代码不同部分的种类值很少),从而避免了函数调用中虚拟参数和实际参数之间种类值不匹配的常见错误。

【讨论】:

  • 谁推荐的?这是古老的方式,而不是现代的方式。它也不仅仅是关于“精度”。
  • 等等,什么?由谁推荐[2]? 1) 显式优于隐式,2) 种类说明符是最便携的替代方案,3) 8 字节浮点数是关于数据存储而不是精度。
  • 由通用原子公司的托卡马克聚变科学家推荐。他们给出了 GACODE 构建系统中使用的 FORTRAN 编码约定列表。所有最新的通用原子建模代码都遵循这些约定。它们的优点在于,当将代码移植到任何新平台(cori、titan、summit ...)时,只需在 makefile 中设置正确的平台环境变量即可。 GACODE 构建系统已在世界上许多计算机系统上建立。
  • @YoujunHu 一个存储在 8 个字节中的实数 可以(并且可能显然会)比 4 个字节更准确,但这是否说明了它的精确度是?多少位小数?最大指数?如果您关心精度方面的特定要求,请使用selected_real_kind。如果您关心特定的存储大小,请使用iso_fortran_env 种类常量。详情请参阅this answer
  • 我并不是说 -fdefault-real-8 是邪恶的,我是说这不是 Fortran 社区最推荐的方法,因为它隐式地改变了您在看看代码。帮助论坛充满了:“当函数的签名似乎与传递的参数匹配时,为什么我对库(Lapack、mkl...)的调用失败或给出错误的结果?”。哦,这是因为makefile中有一行(完全远离源代码)说,在这个项目中,double precision实际上意味着double double precision... ¬¬
【解决方案2】:

种类的一个用途可能是确保对于不同的机器或操作系统,它们真正使用相同的精度并且结果应该相同。所以代码是可移植的。例如,

integer, parameter :: r8 = selected_real_kind(15,9) 
real(kind=r8) :: a

现在这个变量 a 始终是 r8 类型,这是一个真正的“双精度”(因此它在电子计算机上占用 64 位内存),无论代码运行在什么机器/操作系统上。

此外,因此您可以编写如下内容,

a = 1.0_r8

这个_r8确保1.0转换为r8类型。

【讨论】:

  • 为什么a 对于每个处理器都保证为 8 字节实数?
  • 这是错误的。不同的机器可能使用一些非 IEEE 浮点类型。唉,8 字节浮点数甚至可能在这样的机器上不存在,但机器仍然可以有一个符合 Fortran 90 的编译器。
  • selected_real_kind 根本与存储大小无关。您在 HPC 中做什么并不重要。它与数值精度有关。它说明了数字的大小和精确度。我再说一遍,一个符合 Fortran 的处理器可以存在于一台机器上,甚至不需要任何 8 字节类型。那些拥有它的人将在iso_fortran_env 中定义real64,这是定义真正的8 字节实数的真正方法。如果有符合 IEEE 的 8-type 可用,则可以使用 ieee_selected_real_kind,其中数值精度和存储大小的对应关系更加确定。
  • 我并不是说您所做的在当今时代的典型 IEEE 合规机器上对您不起作用。我是说 “无论在什么机器/操作系统上运行,它都是真正的 8(意味着使用 8 字节)类型。” 从语言律师的角度来看是不正确的。它也不保证结果是一样的。
  • 在此答案中使用 selected_real_kind 您已要求最小的十进制精度和范围。您没有要求存储大小、基数、IEEE 一致性或确切的范围和精度。 Fortran 语言中没有任何内容表明您将使用此类参数获得 8 字节实数。
【解决方案3】:

只是扩展其他(非常好的)答案,特别是Andrej Panjkov的答案:

变量的种类是一个整数标签,它告诉编译器 它应该使用哪些受支持的类型。

没错。尽管对于所有 numeric intrinsic 类型,KIND 参数用于指定“处理器上数字的表示和行为模型”(来自第16.5 的标准),实际上是指他们的位模型,这不是 KIND 参数可能代表的唯一内容。

类型的 KIND 参数是在其性质、模型或行为方面任何变化,可供程序员在编译时选择。例如,对于固有字符类型,kind 参数表示处理器上可用的字符集(ASCII、UCS-4、...)。

您甚至可以在定义的派生类型上定义您自己的模型/行为变体(之后从 Fortran 2003 开始​​)。您可以创建一个 Transform Matrix 类型,并为 2D 空间(其中基础数组为 3x3)和 KIND=3 的 3D 空间(具有 4x4 基础数组)提供 KIND=2 的版本。请记住,非固有类型没有自动类型转换。

【讨论】:

    【解决方案4】:

    变量的种类是一个整数标签,它告诉编译器它应该使用它支持的种类。

    请注意,虽然常见 KIND 参数与存储在该 KIND 变量中的字节数相同,但 不需要 Fortran 标准。

    也就是说,在很多系统上,

    REAl(KIND=4) :: xs   ! 4 byte ieee float
    REAl(KIND=8) :: xd   ! 8 byte ieee float
    REAl(KIND=16) :: xq   ! 16 byte ieee float
    

    但可能有编译器,例如:

    REAL(KIND=1) :: XS   ! 4 BYTE FLOAT
    REAL(KIND=2) :: XD   ! 8 BYTE FLOAT
    REAL(KIND=3) :: XQ   ! 16 BYTE FLOAT
    

    对于整数和逻辑类型也是如此。

    (如果我去挖掘,我可能会找到示例。在 usenet 组 comp.lang.fortran 中搜索 kind 以查找示例。关于 Fortran 的最有见地的讨论发生在那里,一些经验丰富的人做出了贡献。)

    所以,如果您不能指望某个特定类型的值在不同平台上为您提供相同的数据表示,您会怎么做?这就是 SELECTED_REAL_KINDSELECTED_INT_KIND 的内在函数的用途。基本上,你告诉函数你需要能够表示什么样的数字,它会返回你需要使用的那种。

    我通常使用这些类型,因为它们通常给我 4 字节和 8 字节实数:

    !--! specific precisions, usually same as real and double precision
    integer, parameter :: r6 = selected_real_kind(6) 
    integer, parameter :: r15 = selected_real_kind(15) 
    

    所以我可能随后将一个变量声明为:

    real(kind=r15) :: xd
    

    请注意,这可能会导致您使用混合语言程序时出现问题,并且您需要绝对指定变量占用的字节数。如果您需要确定,有查询内在函数会告诉您每种类型,您可以从中推断出变量的内存占用、其精度、指数范围等。或者,您可以恢复为非标准但司空见惯的real*4real*8 等声明样式。

    当您开始使用新编译器时,有必要查看编译器特定的种类值,以便了解您正在处理的内容。在网上搜索kindfinder.f90 寻找一个方便的程序,它会告诉你编译器可用的种类。

    【讨论】:

    • 感谢您指出 KIND 是 not KIND= - 您见过现代编译器吗?那个 kindfinder.f90 程序很酷。
    • 搜索 usenet 出现:salford f95 编译器使用种类 1,2 和 3 来代表 2-4-和 8-字节变量;我看到有人声称 g77 在 g95 和 gfortran 出现之前做了同样的事情;还有一份报告称 NAG fortran 编译器有一个编译器开关,允许在 (1,2,3,4) 方案和 (1,2,4,8) 方案之间进行选择。毫无疑问还有其他人。是的,kindfinder 很方便。您可以使用它来设置一个特定于站点的模块文件,其中包含不同类型的命名参数,这样您的真实程序就不会被不可移植的幻数所困扰。
    • 如果你真的想通过它们的存储字节来指定类型,Fortran 2003 有 ISO_C_Binding,它提供了与 C 类型相对应的种类值,其中一些指定了存储大小。 Fortran 2008 在 ISO_FORTRAN_ENV 模块中提供了类型,例如 32 位的 real32 kind 值,64 位的 real64 等。这些具有可移植的优点,至少只要您拥有 Fortran 2003 或 2008编译器。有关这两个模块中的种类列表,请参阅 gfortran 手册。
    • REAL(n)REAL(kind=n) 他们总是一样的,对吧?
    • @Eular 迟到了,但我目前正在熟悉这些,我发现了这个:fortranwiki.org/fortran/show/Real+precision 在第一个块中,a 和 b 分别使用 real(kind=dp)real(dp) 声明,看来它们的意思是一样的。
    【解决方案5】:

    我建议使用 Fortran 2008 及更高版本; INT8, INT16, INT32, INT64, REAL32, REAL64, REAL128。这是通过在 Fortran 2003 及更高版本中调用 ISO_FORTRAN_ENV 来完成的。种类参数提供了不一致的方式来确保您始终获得适当数量的位表示

    【讨论】:

    • int8 确实(如果有适当的种类可用)指定种类参数。我怀疑你的意思是应该更喜欢这个而不是一个明确的数字,比如int(kind=1)? [无论如何,后者都是不好的做法。]也许你可以澄清一下?
    • 我同意你的评论@francescalus
    • @francescalus,让这个问题成为一个规范问题并有一个单一的“社区答案”来总结各种版本的 fortran 的所有故事是否有用?我经常看到我想引用这样一个完整的规范答案的代码。这是这里最好的地方,但信息完全分散在不同的答案和各种 cmet 中。 (抱歉,这是我想出的联系您的最佳方式)
    • @kvantour,关于规范问题(范围、愿望等)的讨论非常适合 Meta SO。你可能会得到更多的不仅仅是我的意见。那就是如果您认为问题本身需要解决:如果您认为此处的答案可以解决问题,那么将所有内容组合成一个完整的形式几乎没有什么坏处。
    • -1。 software.intel.com/content/www/us/en/develop/blogs/… -- TLDR:使用SELECTED_REAL_KIND()
    【解决方案6】:

    来自 Portland Group Fortran 参考KIND 参数“指定内在数据类型的精度”。因此,在声明中

    real(kind=4) :: float32
    real(kind=8) :: float64
    

    变量 float64 声明为 8 字节实数(旧 Fortran DOUBLE PRECISION),变量 float32 声明为 4 字节实数(旧 Fortran REAL)。

    这很好,因为它允许您独立于正在运行的编译器和机器来固定变量的精度。如果您正在运行的计算需要比传统的 IEEE 单精度实数更高的精度(如果您正在参加数值分析课程,这很可能),但将您的变量声明为 real :: myVar,您将如果编译器将所有real 值默认设置为双精度,则很好,但更改编译器选项或将代码移动到具有不同默认大小的不同机器上,realinteger 变量将导致一些可能令人讨厌惊喜(例如,您的迭代矩阵求解器崩溃了)。

    Fortran 还包括一些函数,可以帮助您选择 KIND 参数来满足您的需求 - SELECTED_INT_KINDSELECTED_REAL_KIND - 但如果您只是在学习,我现在不会担心这些。

    既然您提到您正在学习 Fortran 作为课程的一部分,您还应该在 Fortran resources 上看到这个问题,并且可能查看您正在使用的编译器套件(例如 Portland Group 或 Intel)中的参考手册- 这些通常是免费提供的。

    【讨论】:

    • 不,这不是便携式的。请不要向初学者推荐它。
    猜你喜欢
    • 2011-03-08
    • 1970-01-01
    • 1970-01-01
    • 2015-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-27
    • 2016-12-15
    相关资源
    最近更新 更多