【问题标题】:Fortran: the largest and the smallest integerFortran:最大和最小整数
【发布时间】:2012-03-05 15:58:20
【问题描述】:

Fortran 对我来说是全新的,有人可以帮我解决以下问题吗?我想在我的电脑上找出所有整数种类数以及每个种类数的最大值和最小值。我的代码如下:

program intkind
implicit none

integer :: n=1
integer :: integer_range =1


do while(integer_range /= -1)
    print*, "kind_number ", selected_int_kind(n)
    call rang(integer_range)
    n = n *2
    integer_range = selected_int_kind(n)
end do

contains
subroutine rang(largest) 
    integer largest
    print*, huge(largest)

end subroutine

end 

我得到的整数种类数是:1,2,4,8。

  1. 为什么每个种类数的每个最大整数都相同:2147483647?最小整数是否有内在函数?

  2. 当调用子程序rang 时,如何保持整数种类编号?我认为它是最大整数的关键。

【问题讨论】:

  • 只是为了后来才发现的人。虽然没有内在函数,但您始终可以使用 -huge(n) 来计算可用的最小整数。

标签: fortran fortran95


【解决方案1】:

你的子程序:

subroutine rang(largest) 
    integer :: largest
    print *, huge(largest)
end subroutine

将默认大小的整数作为输入,并打印适合该默认大小整数的最大可能值。它将总是返回巨大的(默认整数),在大多数系统上,巨大的(4 字节整数)或 2147483647。huge 只考虑变量类型;它不会以任何方式解释变量。您可以执行上述操作的唯一方法是使用参数化派生类型,这些派生类型足够新,以至于在编译器中对它的支持仍然有点参差不齐。

如果您想查看不同种类的 INTEGER 的范围,则必须使用不同的变量:

program integerkinds
    use iso_fortran_env
    implicit none

    integer :: i
    integer(kind=int8)  :: i8
    integer(kind=int16) :: i16
    integer(kind=int32) :: i32
    integer(kind=int64) :: i64

    integer(kind=selected_int_kind(6)) :: j6
    integer(kind=selected_int_kind(15)):: j15

    print *,'Default:'
    print *, huge(i)
    print *,'Int8:'
    print *, huge(i8)
    print *,'Int16:'
    print *, huge(i16)
    print *,'Int32:'
    print *, huge(i32)
    print *,'Int64:'
    print *, huge(i64)

    print *,''

    print *,'Selected Integer Kind 6:'
    print *, huge(j6)

    print *,'Selected Integer Kind 15:'
    print *, huge(j15)

end program integerkinds

跑步给出:

$ ./intkinds
 Default:
  2147483647
 Int8:
  127
 Int16:
  32767
 Int32:
  2147483647
 Int64:
  9223372036854775807

 Selected Integer Kind 6:
  2147483647
 Selected Integer Kind 15:
  9223372036854775807

【讨论】:

  • IF: selected_int_kind(9) = 4 ,integer(kind=selected_int_kind(9)) :: j4 and huge(j4) is:2147483647 在我的电脑上。 selected_int_kind(r) 的定义表明它可以表示 -10r 10r 范围内的所有整数值 n。如果 r =9,那么最大值是 10**9-1,小于 2147483647(huge(j4)),为什么?我无法理解。
  • 第一部分:是的,huge(j4) 应该是 2147483647,因为 j4 被定义为整数(kind=selected_int_kind(9))。但请注意,您必须定义 j4 是那种类型。您不能在定义变量后更改种类;例如,之后您可以根据需要多次调用 selected_int_kind() 并且它不会改变任何内容。上面的示例向您展示了如何定义各种类型。
【解决方案2】:

纯粹作为附录或替代观点,Fortran 变量是根据分配给 var 的内存字节数定义的。事实上,所有可比较的编译器都根据分配的字节数来定义 vars,否则系统将很难在内存中分配/存储,并且如果没有这些,就很难执行算术等。

对于像我这样的一些人来说,使用稍旧的符号(而不是“kind konfusion”)更容易看到发生了什么。特别是,很多编译器提供了 Kind 和 bytes 之间的直接 1:1 对应关系/var,然后使最大/最小整数的计算相当简单(一些编译器使用非线性或非直接对应)。但请务必注意最后的可移植性帮助。例如

Integer(1)      :: Int1     ! corresponds to  a 1 byte integer
Integer(2)      :: Int1     ! corresponds to  a 2 byte integer
Integer(4)      :: Int1     ! corresponds to  a 4 byte integer
Integer(8)      :: Int1     ! corresponds to  an 8 byte integer

类似的符号适用于其他 Fortran 类型(Real、Logical 等)。如果未指定“大小”,则所有 var 类型都有一个默认分配的字节数。

特定类型的最大字节数还取决于编译器和系统(例如,Integer(16) 并非在所有系统上都可用,等等)。

一个字节是 8 位,所以一个字节应该能够容纳最大值 2^8 = 256 如果从 1 开始编号,或 = 255 从 0 开始。

但是,在 Fortran 中,(几乎所有)数字变量都是“有符号的”。这意味着在位表示中的某处需要一位来跟踪该数字是 +ve 数字还是 -ve 数字。因此,在本例中,最大值为 2^7,因为“符号”信息的一位“丢失/保留”。因此,带符号的 1 字节整数的可能值为 -127:+128(注意 Abs(limits) 总和为 255,因为“0”占据了一个位置,总共 256 个“事物”,因为它应该是)。

类似的规则适用于所有此类变量,只是指数“n”,在 2^n 中,根据字节数而变化。例如,一个 Integer(8) var 有 8 个字节或 64 位,其中 1 位丢失/保留用于符号信息,因此如果从 1 开始编号,则最大可能值为 2^63 = 9223372036854775808,或者在开始时 = 4611686018427387904从 0 开始。

标准的整数数据模型可以概括为:

IntNum = s * Sum[ w(k) * 2 ^ (k-1), k=1:(NumBytes*8)-1], 

其中 s = "sign" (+/-1),对于第 k 位值,w(k) 为 1 或 0。

不需要在类型声明中使用显式数字或环境变量;允许使用用户定义的编译时间常量(即参数)。例如

Integer, Parameter        :: DP = Kind(1.0d0)    ! a standard Double Precision/8-byte declaration
Integer, Parameter        :: I4B = 4             ! NOTICE, here the "Integer" bit has not been explicitly "sized", so defaults to "Integer(4)"
!
Real(DP)                  :: ADoublePrecReal     ! an 8-byte Real (approx 15 decimal places with exp +/- approx 300, see Real data model)
!
Integer(I4B)              :: AStandardInt        ! a 4-byte integer.

由于 Parameter 语句可以在另一个通过 Use 等访问的模块中,重新编译大型复杂代码以获得所需的“精度”的替代定义是一件简单的事情。例如,如果将 DP 编辑为 Kind(1.0),则应用该声明的任何地方都将变为“单精度”Real。

Fortran 内部函数 Huge()、Tiny() 等有助于确定给定系统上的可能性。

使用 Fortran“位”内在函数和其他工具/方法可以完成更多工作。

【讨论】:

  • 这个答案一开始是错误的:Fortran 变量没有根据它们占用的字节数来定义。种类选择器,如integer(8)real(4) 等表达式中的整数,仅标识编译器支持的种类之一。例如,NAG Fortran 编译器默认为 integer(2) 用于 4 字节整数,integer(3) 用于 8 字节整数。编译器通常会使用与使用的字节数相匹配的种类选择器,但这不是标准所要求的。
  • 这是一个常见的误解。另见stackoverflow.com/questions/3170239/…
  • 是的,每个编译器供应商都可以做他们喜欢做的事情,而且经常做。是的,多强调系统之间的差异会有所帮助(显然,一次对某些人来说是不够的)。尽管如此,最初制作的 cmets 对于来自 Compaq、DEC、IBM、CRAY、Oracle、Intel 等的编译器是正确的,其种类/字节完全对应。我还强调了将全局参数用于 Kind 作为良好实践,原因与其他人仅在病后引用的原因相同。此外,可以肯定整数数据模型公式是正确的,请查看任何书籍..
  • 您现在已经编辑了答案,但它仍然指出 Fortran 变量是根据分配给 var 的内存字节数定义的。它们可能是,但不要求它们必须是。 Fortran 已经在 byte 可能是一个陌生概念的机器上实现了,我毫不怀疑它会在未来再次在这样的机器上实现。
  • 您说double precision 实数必须是 8 个字节也是不正确的。最新标准要求双精度实数比默认实数具有更高的精度,并且它至少具有 10 个十进制数字的精度和 +/- 37 的指数范围。但是该标准对处理器如何(使用标准的语言)是为了提供这种精度。我认为当前所有的 Fortran 编译器都实现了 8 个字节的双精度实数,但这只是该语言悠久历史和未来的一个瞬间。
猜你喜欢
  • 2013-06-27
  • 2012-11-07
  • 2012-04-09
  • 2012-11-20
  • 2012-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-06
相关资源
最近更新 更多