Fortran 90 kind参数

54

我对Fortran 90中的kind参数感到困惑。据我所知,它既不能确定变量的精度(即float或double),也不能确定变量的类型。

那么,它到底是用来干什么的?它确定了什么?


你是指Kind标记吗? - TStamper
6个回答

69

变量的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_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 * 4real * 8等声明样式。
当您开始使用新编译器时,值得查看编译器特定的类型值,以便了解正在处理的内容。搜索网络上的kindfinder.f90,获取一个便利程序,以告诉您编译器可用的类型。

4
谢谢指出KIND不是KIND=<我想要的字节数>,你看过现代编译器是否采用这种方式?那个kindfinder.f90程序非常棒。 - Tim Whitcomb
6
搜索usenet可以发现:Salford F95编译器使用kind 1、2和3来代表2字节、4字节和8字节变量;我看到有人声称g77在g95和gfortran出现之前也是这样做的;还有一份报告称NAG Fortran编译器有一个编译器开关,允许在(1,2,3,4)方案和(1,2,4,8)方案之间进行选择。毫无疑问,还有其他情况。是的,Kindfinder很方便。您可以使用它设置一个特定于站点的模块文件,其中包含不同种类的命名参数,以便您的真实程序没有被非可移植的幻数所污染。 - Andrej Panjkov
7
如果你真的想通过存储字节来指定类型,Fortran 2003有ISO_C_Binding,提供对应于C类型的kind值,其中一些指定了存储大小。Fortran 2008在ISO_FORTRAN_ENV模块中提供了类型,例如32位的real32 kind值,64位的real64等等。这些类型的优点是可移植性强,至少只要有Fortran 2003或2008编译器即可。请参考gfortran手册中这两个模块中kind的列表。 - M. S. B.
REAL(n)REAL(kind=n)它们总是同一个东西,对吗? - Eular
1
@ Eular 迟来的,但我正在熟悉这些内容,并找到了这个网站:http://fortranwiki.org/fortran/show/Real+precision。在第一个块中,使用 real(kind=dp)real(dp) 声明了 a 和 b,它们看起来意思相同。 - ZeroTwo
2
@ZeroTwo 是的,它们确实有区别。在这里要注意字符种类,第一个数字表示长度。character(4) 表示长度为 4 的字符串。character(c_char) 表示长度为 c_char 的字符串。character(kind=c_char) 表示长度为 1 的单个字符。 - Vladimir F Героям слава

11

我建议使用Fortran 2008或更新版本; INT8, INT16, INT32, INT64, REAL32, REAL64, REAL128。这可以通过在Fortran 2003或更新版本中调用ISO_FORTRAN_ENV来实现。Kind参数提供的方式不一致,无法确保总是获得适当的位数表示。


如果有适当的类型参数,int8会指定一个类型参数。我猜你的意思是应该优先选择它,而不是像 int(kind=1) 这样显式地使用数字?(无论如何,后者都是不好的实践。)也许你可以澄清一下? - francescalus
我同意你的评论 @francescalus - Zeus
@francescalus,将这个问题变成一个规范问题,并有一个单一的“社区答案”,总结各种版本的Fortran的整个故事,这不是很有用吗?我经常看到代码,我想参考这样一个完整的规范答案。这是最好的地方,但信息完全分散在不同的答案和各种评论中。(抱歉,这是我找到与您联系的最佳方式) - kvantour
@kvantour,关于规范问题(范围、需求等)的讨论非常适合在Meta SO上进行。你可能会得到不止我的意见。如果你认为问题本身需要改进,那么可以将所有内容整合成完整的形式,如果你认为这里的答案解决了问题,那么也没有什么坏处。 - francescalus
-1. https://software.intel.com/content/www/us/en/develop/blogs/doctor-fortran-in-it-takes-all-kinds.html -- 简而言之:使用 SELECTED_REAL_KIND() - André Chalella
这个答案的主要问题是,尽管它得到了很多赞,但它根本没有试图回答问题。它只是给出了一些关于哪种参数选择可能是最好的的意见。 - Vladimir F Героям слава

4
只是扩展了其他(非常好的)回答,特别是Andrej Panjkov的回答:
变量的类型是一个整数标签,它告诉编译器应该使用其支持的哪种类型。
确切地说,即使对于所有的数值内部类型,KIND参数也用于指定“处理器上数字表示和行为的模型”(来自标准的16.5节),实际上意味着它们的位模型,但这不是KIND参数可能表示的唯一内容。
类型的KIND参数是可用于编译时选择的其性质、模型或行为的任何变化。例如,对于内置字符类型,kind参数表示在处理器上可用的字符集(ASCII、UCS-4等)。
您甚至可以在您定义的派生类型(从Fortran 2003以后)中定义自己的模型/行为变化。您可以创建一个转换矩阵类型,并具有KIND=2的2D空间版本(其中基础数组将为3x3),并具有KIND=3的3D空间版本(其中基础数组将为4x4)。只需记住,对于非内部类型没有自动的类型转换。

2

从《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 资源上的这个问题,并可能查看您正在使用的编译器套件(例如 Portland Group 或 Intel)的参考手册 - 这些通常是免费提供的。

4
不行,这不是便携的。请不要向初学者推荐它。 - Vladimir F Героям слава

-2

kind 的一个用途是确保在不同的机器或操作系统上,它们真正使用相同的精度,并且结果应该是相同的。因此代码是可移植的。例如:

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

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

因此,您可以编写类似以下的内容:

a = 1.0_r8

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


4
这完全是错误的。不同的机器可能会使用一些非IEEE浮点类型。遗憾的是,8字节浮点数在这样的机器上甚至可能不存在,但该机器仍然可以拥有一个符合Fortran 90标准的编译器。 - Vladimir F Героям слава
1
我并不是说你现在使用的IEEE兼容机器上的方案无法运行。我想说的是,从语言专家的角度来看,“无论在什么机器/操作系统上,这是真正的8(即使用了8字节)类型”这一声明是不正确的。同时它也不能保证结果会相同。 - Vladimir F Героям слава
3
在这个回答中,使用了 selected_real_kind ,你要求的是最小十进制精度和范围。你并没有要求存储大小、基数、IEEE 符合性或完全的范围和精度。在 Fortran 语言中,并没有规定你将会得到一个具有此种类参数的 8 字节实数。 - francescalus
1
它在你的编译器上返回什么并不重要。顺便说一句,正如最高得票答案所示,它将在其他某些编译器上返回2。selected_real_kind()不会返回字节数。storage_size()返回的是位数。我再说一遍,selected_real_kind()不是用于选择任何字节的,而是用于选择数字精度、基数等。这就是最高得票答案,我也点赞了,非常好地解释了这一点。请再次阅读它,因为你还没有理解它。 - Vladimir F Героям слава
1
NAG编译器默认返回2,有一个选项可以让它返回202(或其他一些大数字,我不记得是哪个了,但这是因为确切的数字完全无关紧要)。无论如何,Fortran编译器不需要提供比10更大的实际十进制精度,也不需要提供具有8字节存储的实数。如果您不同意这些观点,则进一步讨论将毫无意义。 - francescalus
显示剩余15条评论

-8
总结其他答案:kind参数指定内置数据类型(如整数和实数)的存储大小(因此间接指定精度)。
然而,现在推荐的方法不是在源代码中指定变量的kind值,而是使用编译器选项来指定所需的精度。例如,我们在代码中写入:real :: abc,然后使用编译选项-fdefault-real-8(对于gfortran)编译代码,以指定一个8字节的浮点数。对于ifort,相应的选项是-r8
更新:
看起来Fortran专家们强烈反对上述推荐的方法。尽管如此,我仍然认为上述方法是一种好的实践,有助于减少在Fortran代码中引入错误的机会,因为它保证您在整个程序中使用相同的kind-value(在代码的不同部分需要使用不同的kind-value的机会很少),从而避免了函数调用中虚参和实参之间经常遇到的kind-value不匹配的错误。

3
由谁推荐?这是一种古老的方式,而不是现代方式。这也不仅仅关乎“精确度”。 - Vladimir F Героям слава
等等,什么?由谁推荐的[2]?1)显式优于隐式,2)种类说明符是最便携的选择,3)8字节浮点数与数据存储有关,而不是精度。 - Rodrigo Rodrigues
这些FORTRAN编码约定是由General Atomics的托卡马克聚变科学家推荐的。所有最新的General Atomics建模代码都遵循这些约定。它们的好处在于,当将代码移植到任何新平台(cori、titan、summit等)时,只需要在makefile中设置正确的平台环境变量即可。GACODE构建系统已经在世界上许多计算机系统上设置。 - Youjun Hu
1
@YoujunHu 一个存储在8个字节中的实数可能会(显然)比4个字节更精确,但这是否意味着它有多精确?有多少小数位?最大指数是多少?如果您关心特定的精度要求,请使用selected_real_kind。如果您关心特定的存储大小,请使用iso_fortran_env类型常量。有关更多详细信息,请参阅此答案 - Rodrigo Rodrigues
2
我并不是说-fdefault-real-8是邪恶的,我是在说这不是Fortran社区最推荐的方法,因为当你查看代码时,它隐含地改变了你期望的行为。求助论坛上到处都是这样的问题:_“为什么我的库调用(Lapack、mkl等)在函数签名似乎匹配传递的参数时失败或给出错误的结果?”_哦,这是因为在makefile中有一行(与源代码完全不相关),它说在这个项目中,double precision实际上意味着double double precision... ¬¬ - Rodrigo Rodrigues
显示剩余2条评论

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