我无法理解 Fortran 90 的kind
参数。据我所知,它不能确定变量的精度(即浮点数或双精度),也不能确定变量的类型。
那么,它决定了什么,它到底是为了什么?
变量的种类是一个整数标签,它告诉编译器它应该使用它支持的种类。
请注意,尽管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.fortrankind
以查找示例。关于 Fortran 的最有见地的讨论发生在那里,一些经验丰富的人做出了贡献。)
所以,如果你不能指望一个特定的类型值在不同的平台上给你相同的数据表示,你会怎么做?这就是内在功能SELECTED_REAL_KIND
和SELECTED_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*4
, real*8
etc 声明风格。
当您开始使用新的编译器时,有必要查看编译器特定的类型值,以便了解您正在处理的内容。在网上搜索kindfinder.f90
一个方便的程序,它会告诉你编译器可用的种类。
我建议使用 Fortran 2008 及更高版本;INT8, INT16, INT32, INT64, REAL32, REAL64, REAL128
. 这是通过调用ISO_FORTRAN_ENV
Fortran 2003 及更高版本来完成的。种类参数提供了不一致的方式来确保您始终获得适当数量的位表示
只是扩展其他(非常好的)答案,特别是Andrej Panjkov的答案:
变量的种类是一个整数标签,它告诉编译器它应该使用它支持的种类。
确切地。即使对于所有数字内在类型,KIND 参数用于指定“处理器上数字表示和行为的模型”(来自标准第 16.5 节的词),实际上意味着它们的位模型,这不是 KIND 参数可能代表的唯一内容。
类型的 KIND 参数是其性质、模型或行为的任何变化,可供程序员在编译时选择。例如,对于固有字符类型,kind 参数表示处理器上可用的字符集(ASCII、UCS-4、...)。
你甚至可以在你定义的派生类型上定义你自己的模型/行为变体(从 Fortran 2003 之后)。您可以创建一个 Transform Matrix 类型,并为 2D 空间(其中基础数组为 3x3)和 KIND=3 的 3D 空间(具有 4x4 基础数组)提供 KIND=2 的版本。请记住,非固有类型没有自动类型转换。
From the Portland Group Fortran Reference, the KIND
parameter "specifies a precision for intrinsic data types." Thus, in the declaration
real(kind=4) :: float32
real(kind=8) :: float64
the variable float64
declared as an 8-byte real (the old Fortran DOUBLE PRECISION
) and the variable float32
is declared as a 4-byte real (the old Fortran REAL
).
This is nice because it allows you to fix the precision for your variables independent of the compiler and machine you are running on. If you are running a computation that requires more precision that the traditional IEEE-single-precision real (which, if you're taking a numerical analysis class, is very probable), but declare your variable as real :: myVar
, you'll be fine if the compiler is set to default all real
values to double-precision, but changing the compiler options or moving your code to a different machine with different default sizes for real
and integer
variables will lead to some possibly nasty surprises (e.g. your iterative matrix solver blows up).
Fortran also includes some functions that will help pick a KIND
parameter to be what you need - SELECTED_INT_KIND
and SELECTED_REAL_KIND
- but if you are just learning I wouldn't worry about those at this point.
Since you mentioned that you're learning Fortran as part of a class, you should also see this question on Fortran resources and maybe look at the reference manuals from the compiler suite that you are using (e.g. Portland Group or Intel) - these are usually freely available.
kind 的用途之一可能是确保对于不同的机器或操作系统,它们真正使用相同的精度并且结果应该相同。所以代码是可移植的。例如,
integer, parameter :: r8 = selected_real_kind(15,9)
real(kind=r8) :: a
现在这个变量 a 始终是 r8 类型,这是一个真正的“双精度”(因此它在电子计算机上占用 64 位内存),无论代码在什么机器/操作系统上运行。
此外,因此您可以编写如下内容,
a = 1.0_r8
这个 _r8 确保将 1.0 转换为 r8 类型。
总结其他答案: kind 参数指定了固有数据类型(例如整数和实数)的存储大小(因此间接地指定了精度)。
但是,现在推荐的方法不是在源代码中指定变量的种类值,而是使用编译器选项来指定我们想要的精度。例如,我们在代码中编写:real :: abc
然后使用编译选项-fdefault-real-8
(对于 gfortran)指定一个 8 字节浮点数来编译代码。对于 ifort,对应的选项是-r8
。
更新:
似乎这里的 Fortran 专家强烈反对上述推荐的方式。尽管如此,我仍然认为上述方法是一种很好的做法,有助于减少在 Fortran 代码中引入错误的机会,因为它保证您在整个程序中使用相同的种类值(您确实需要使用不同的代码不同部分的种类值很少),从而避免了函数调用中虚拟参数和实际参数之间种类值不匹配的常见错误。