【问题标题】:Fortran: integer*4 vs integer(4) vs integer(kind=4)Fortran:整数 * 4 与整数(4)与整数(种类 = 4)
【发布时间】:2011-03-11 08:37:07
【问题描述】:

我正在努力学习 Fortran,我看到很多不同的定义被传递,我想知道他们是否正在尝试完成同样的事情。以下有什么区别?

  • integer*4
  • integer(4)
  • integer(kind=4)

【问题讨论】:

    标签: fortran language-lawyer


    【解决方案1】:

    在 Fortran >=90 中,最好的方法是使用内部函数来指定所需的精度——这既保证了可移植性,又保证了您获得所需的精度。例如,要获得至少支持 8 个十进制数字的整数 imy_int,您可以使用:

    integer, parameter :: RegInt_K = selected_int_kind (8)
    integer (kind=RegInt_K) :: i, my_int
    

    RegInt_K(或您选择的任何名称)定义为parameter,您可以在整个代码中将其用作符号。这也使更改精度变得容易。

    请求 8 位或 9 位十进制数字通常会获得一个 4 字节整数。

    integer*4 是一个常见的扩展,可以追溯到旧的 FORTRAN 以指定一个 4 字节整数。虽然,这种语法不是,也从来不是标准的 Fortran。

    integer (4)integer (RegInt_K)integer (kind=4)integer (kind=RegInt_K) 的缩写。 integer (4)integer*4 不同,并且不可移植——语言标准没有指定种类的数值。大多数编译器将kind=4 用于4 字节整数——因为这些编译器integer*4integer(4) 将提供相同的整数类型——但也有例外,因此integer(4) 是不可移植的,最好避免使用。

    实数的方法类似。

    更新:如果您不想通过所需的精度指定数字类型,而是通过它们将使用的存储来指定,Fortran 2008 提供了一种方法。实数和整数可以通过useISO_FORTRAN_ENV 模块之后的存储位数指定,例如,对于 4 字节(32 位)整数:

    use ISO_FORTRAN_ENV
    integer (int32) :: MyInt
    

    gfortran 手册在“内在模块”下有文档。

    【讨论】:

    • 这是一个绝妙的解释!令人惊叹的!优秀!现在对我来说很清楚了.. :D 非常感谢!
    【解决方案2】:

    只是一个更明确的解释是什么。编译器有一个不同数字类型的表。所有整数类型都与基本类型不同种类 -- integer。假设编译器有 1 字节、2 字节、4 字节、8 字节和 16 字节integer(或real)种类。在表中,编译器对每种类型都有一个索引——这个索引是类型编号。

    许多编译器选择这个编号:

    kind number    number of bytes
    1              1
    2              2
    4              4
    8              8
    16             16
    

    但他们可以选择任何其他编号。一种明显的可能性是

    kind number    number of bytes
    1              1
    2              2
    3              4
    4              8
    5              16
    

    确实有编译器(至少 g77 和 NAG)选择了这种方法。还有一些选项可以改变这一点。因此 kind 数字不可移植 integer(kind=4)integer(4) 表示 4 字节整数或 8 字节整数,具体取决于编译器。

    integer*4 是可移植的,因为它总是意味着 4 个字节。但另一方面,它不是可移植的,因为它从未成为任何标准的一部分。使用这种表示法的程序在 Fortran 77、90 或任何其他 Fortran 中都是无效的。

    要查看如何设置种类编号的正确选项,请参阅 M.S.B. 的回答。

    同样的概念也适用于real 数据类型。请参阅Fortran 90 kind parameter(mataap 的答案)。

    【讨论】:

    • 这里有趣的是,表单 type(kind) 和 type*kind 不能完全互换,需要注意。例如,在 Intel Fortran 中 integer(6) 和 integer*4 相同,但是: COMPLEX([KIND=]4) 与 COMPLEX*8, COMPLEX([KIND=]8) 或 COMPLEX*16, COMPLEX 相同([KIND=]16) 或 COMPLEX*32
    • @syscreat 我没有在这个答案中解决真实和复杂的问题,因为关于它们有一个单独的问题。我在这里只处理整数。请参阅答案和答案中的链接。具有相同精度的实数和复数具有相同种类的数字这一事实是由标准强制规定的。
    【解决方案3】:

    我将参考@SteveLionel 最近写的this enlightening article,并尝试涵盖迄今为止其他答案中没有的一些细节:


    1. integer*nreal*n 中显示的语法是很久以前编译器提供的常见扩展,当时不同的计算机体系结构开始对整数和实数值的内存格式进行不同的设计,其中n 是存储值的大小(以字节为单位)。但是,这并没有说明这些值的范围或精度:例如,16 位整数的不同实现可以提供不同的范围和限制值。

    寄存器大小可以是 8、12、16、30、32、36、48、60 或 64 位,一些 CDC 机器有补码整数(整数允许负零!),PDP-11 行有根据系列的不同,有几种不同的浮点格式,IBM 360/370 对其浮点进行了“十六进制规范化”等 [...] 这些扩展非常受欢迎,以至于许多程序员认为(甚至今天也有很多人认为)这种语法是标准的 Fortran;不是!


    1. 当 Fortran 90 出现时,kind 参数被添加到语言中,以及内部查询函数(特别是 kindselected_int_kindselected_real_kind,还有其他的,例如 precisiondigits , epsilon...) 帮助程序员指定数字类型的精度和范围的最低要求(仍然没有官方提及存储模型或字节)。语法是integer(kind=n) 甚至integer(n),其中n 是一个常量值,对应于编译器支持的一种整数。对于文字常量,语法为 12_n3.4e-2_n

      这个解决方案的优点是 Fortran 没有(现在仍然没有)对数据类型的实现细节做出任何假设,而不是用于选择类型的查询函数的结果,所以代码是由正在解决的问题参数化,而不是由语言或硬件参数化。问题是,正如其他答案中所说,每个编译器都可以选择他们的种类数,因此假设像 integer(4) 这样的幻数是不可移植的。


    1. Fortran 90 还引入了默认种类 的概念,这就是您在不指定种类时得到的。

    默认种类依赖于实现,尽管从 Fortran 2008 开始,编译器只需要支持一种整数种类和两种实数种类。 (在 Fortran 2018 中仍然如此,但还有一个附加要求,即至少一个整数种类支持 18 个十进制数字。)如果您编写一个没有种类说明符的常量文字,您将获得默认种类。


    1. 借助 Fortran 2003 和包含的内部模块 ieee_arithmetic,您可以查询并选择具有 IEEE 浮点功能的实数类型(如果可用)。

    有些架构同时提供 IEEE 和非 IEEE 浮点类型,例如 HP(以前的 Compaq,以前的 DEC)Alpha。在这种情况下,您可以使用内部模块 IEEE_ARITHMETIC 中的 IEEE_SELECTED_REAL_KIND 来获得 IEEE 浮动类型。如果没有满足要求的受支持种类怎么办?在这种情况下,内在函数返回一个负数,这将(通常取决于上下文)触发编译时错误。


    1. 最后,Fortran 2003 带来了 iso_fortran_env 内在模块,该模块具有查询编译器实现的类型的存储大小的功能,具有 numeric_storage_sizebit_size 等内在函数。 Fortran 2003 修订版的另一个新增功能是 iso_c_binding 内在模块,它提供了种类参数值以保证在存储、精度和范围方面与 C 类型的兼容性。

    内部模块 ISO_C_BINDING 为可与 C 类型互操作的 Fortran 类型声明常量,例如 C_FLOAT 和 C_INT。如果您要声明可与 C 互操作的变量和接口,请使用这些。


    1. 作为最后一点,我将提到最近的 Fortran 2008 标准,它扩展了内部模块 iso_fortran_env 以包含命名常量 int8int16int32m int64real32、@987654349 @ 和real128,其值对应于占据规定位数的整数类型和实数类型。问题是这些常量只保证存储大小,而不是精度或范围。只有当这正是您想要的时候才使用它们。

    在我看来,这比旧的 *n 扩展要好一点,因为它告诉你一个类型适合那么多位,但没有别的。例如,有一个编译器,其中 REAL128 以 128 位存储,但实际上是旧 x86 浮点堆栈寄存器中使用的 80 位“扩展精度”。如果您使用这些,您可能会认为您使用的是便携式功能,但实际上您并没有,并且当您获得的那种不具备您需要的功能时,您可能会被咬。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-16
      • 1970-01-01
      • 1970-01-01
      • 2015-04-24
      • 1970-01-01
      • 1970-01-01
      • 2012-08-26
      相关资源
      最近更新 更多