Fortran中的integer*4和integer(4)和integer(kind=4)有何区别?

67

我正在尝试学习Fortran,看到了许多不同的定义,不知道它们是不是在尝试完成同样的事情。以下三者之间有什么区别?

  • integer*4
  • integer(4)
  • integer(kind=4)
3个回答

67

在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提供了一种方法。在use ISO_FORTRAN_ENV模块后,可以通过存储位数指定实数和整数类型。例如,对于4字节(32位)整数:

use ISO_FORTRAN_ENV
integer (int32) :: MyInt

那是一个绝妙的解释!太棒了!非常出色!现在对我来说非常清晰.. :D 非常感谢你! - Sam

31

再解释一下“类型”的含义。编译器有一张不同数字类型的表格。所有整数类型都是基本类型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的规范。

要查看如何设置kind数字的正确选项,请参见M.S.B.的答案。

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


3
有趣的是,这里的类型(kind)和类型kind并不完全可互换,需要注意。例如,在英特尔Fortran中,integer(6)和integer4是相同的,但: COMPLEX([KIND=]4)与COMPLEX8相同, COMPLEX([KIND=]8)或COMPLEX16, COMPLEX([KIND=]16)或COMPLEX*32。 - syscreat
2
@syscreat 我在这个答案中没有涉及到实数和复数,因为有一个单独的问题与它们有关。我只讨论了整数。请参见答案末尾的链接。实数和复数具有相同精度的事实是由标准强制规定的,它们具有相同的类型编号。 - Vladimir F Героям слава

6
我将参考最近由@SteveLionel撰写的这篇启发性文章,并尝试涵盖其他答案中尚未提及的一些细节。
  1. integer*nreal*n中显示的语法是很久以前编译器提供的常见扩展,当不同的计算机体系结构开始对整数和实数值的内存格式有不同设计时,n是存储的值的字节大小。然而,这并没有说明这些值的范围或精度:例如,不同的16位整数实现可能提供不同的范围和限制值。

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


当Fortran 90发布时,语言中添加了“kind”参数,以及内部查询函数(特别是“kind”,“selected_int_kind”和“selected_real_kind”,还有其他一些,如“precision”,“digits”,“epsilon”…)来帮助程序员指定数字类型的最低要求(仍然没有官方提及存储模型或字节)。语法是“integer(kind=n)”甚至“integer(n)”,其中“n”是与编译器支持的整数种类相对应的常量值。对于文字常量,语法是“12_n”或“3.4e-2_n”。
这种解决方案的优点是,Fortran不会(至今仍然不会)对除用于选择类型的查询函数结果之外的数据类型实现细节做任何假设,因此代码是根据问题而不是语言或硬件进行参数化的。问题是,正如其他答案中所述,每个编译器都可以选择其种类编号,因此假设像“integer(4)”这样的魔术数字是不可移植的。
此外,Fortran 90 还引入了“默认种类”的概念,即当你没有指定种类时所得到的结果。默认种类是依赖于实现的,尽管直到 Fortran 2008,编译器仅需支持一个整数种类和两个实数种类(在 Fortran 2018 中仍然如此),但增加了一个要求,即至少有一个整数种类支持18位十进制数字。如果您在常量文字中没有指定种类说明符,则将使用默认种类。
有些架构支持IEEE和非IEEE浮点类型,例如HP(前身为Compaq,前身为DEC)Alpha。在这种情况下,您可以使用intrinsic模块IEEE_ARITHMETIC中的IEEE_SELECTED_REAL_KIND来获取一个IEEE浮点类型。如果没有符合要求的支持类型怎么办呢?在这种情况下,内置函数会返回一个负数,这通常会触发编译时错误(根据上下文的不同)。
最后,Fortran 2003引入了iso_fortran_env内置模块,该模块具有用于查询编译器实现的类型的存储大小的函数,例如numeric_storage_sizebit_size。Fortran 2003修订版的另一个新增功能是iso_c_binding内置模块,它提供了与C类型在存储、精度和范围上兼容的kind参数值。

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


作为最后一点,我要提到最新的Fortran 2008标准,该标准扩展了内置模块iso_fortran_env,包括命名常量int8int16int32int64real32real64real128,它们的值对应于占据指定位数的整数和实数类型。需要注意的是,这些常量只能保证存储大小,并不能保证精度或范围。只有在确切需要这样的情况下才使用它们。
在我看来,这比旧的*n扩展要好一点,因为它告诉你一个类型能够容纳多少位,但没有提供其他信息。举个例子,有一个编译器将REAL128存储在128位中,但实际上它是80位的“扩展精度”实数,在旧的x86浮点堆栈寄存器中使用。如果你使用这些常量,可能会认为自己在使用可移植的功能,但实际上并不是这样,当你得到的类型没有你所需的功能时,可能会遇到问题。

在声明变量时,有没有办法指定精度/范围?有些答案似乎声称可以做到,但没有给出示例。 - Youjun Hu
在声明变量时,有没有办法指定精度/范围?有些答案似乎声称可以做到,但没有给出示例。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接