如何将位模式Z'FEDCBA09'分配给32位整数

kva*_*our 2 fortran gfortran

如何Z'FEDCBA09'将最高有效位等于1 的boz-literal-constant 或任何其他位模式分配给整数?

标准规定:

INT(A[,KIND])如果A为boz-literal-constant,则结果的值是根据16.3中的模型,其位序列与根据16.3.3通过填充或截断修改的A的位序列相同的值。最高有效位为1的位序列的解释取决于处理器。

来源:Fortran 2018 Standard

因此,以下分配可能会失败(假定integer默认为32位):

program boz
   implicit none
   integer :: x1 = int(Z'FEDCBA09')
   integer :: x2 = int(Z'FFFFFFFF')
   integer :: x3
   data x3/Z'FFFFFFFF'/
end program
Run Code Online (Sandbox Code Playgroud)

使用gfortran,这仅在添加时起作用,但这会带来-fno-range-check额外的不良影响:

-fno-range-check:禁用在编译过程中对常量表达式的简化结果进行范围检查。例如,当简化时,GNU Fortran将在编译时给出错误。a = 1. / 0.使用此选项,将不会给出错误,并且将为值分配+ Infinity。如果表达式的计算结果超出的相关范围[-HUGE():HUGE()],则该表达式将替换为-Inf+Inf适当替换。类似地,DATA i/Z'FFFFFFFF'/在大多数系统上都会导致整数溢出,但是-fno-range-check该值将“环绕”并且i将被初始化为-1

来源:GNU编译器集合,gfortran手册

我尝试了以下方法,效果很好,但仍然不是100%

integer(kind=INT32) :: x1 = transfer(real(Z'FEDCBA09',kind=REAL32),1_INT32)
integer(kind=INT32) :: x1 = transfer(real(Z'FFFFFFFF',kind=REAL32),1_INT32)
Run Code Online (Sandbox Code Playgroud)

后一种情况对于gfortran失败,因为它抱怨Z'FFFFFFFF'代表NaN。

使用IOR(0,Z'FEDCBA09')也会失败,因为它会转换boz-literalINT

问题:如何使用boz-literal-constant可靠地分配位模式?也就是说,与使用的编译器(GNU,SUN,PGI,NAG等)无关。

答:Jim Rodes当前在此评论中给出了最可靠的答案:

x = ior(ishft(int(Z'FEDC'),bit_size(x)/2),int(Z'BA09'))
Run Code Online (Sandbox Code Playgroud)

这将适用于任何编译器,并且不需要任何其他数据类型即可成功。

小智 5

对于需要-fno-range-check在什么将是gfortran 10.1它被释放时已被删除。在10.1中,您所指定的位模式将被视为32位无符号整数,并强制执行doubles-complement环绕语义。

您的第一个代码段中print添加了一条语句

program boz
  implicit none
  integer :: x1 = int(Z'FEDCBA09')
  integer :: x2 = int(Z'FFFFFFFF')
  integer :: x3
  data x3/Z'FFFFFFFF'/
  print *, x1, x2, x3
end program
Run Code Online (Sandbox Code Playgroud)

产量

$ gfortran -o z file.f90
$ ./z
-19088887  -1 -1
Run Code Online (Sandbox Code Playgroud)

并且不需要该-fno-range-check选项。提议的transfer方法也是如此:

program boz
   use iso_fortran_env
   implicit none
   integer(kind=INT32) :: x1 = &
   &   transfer(real(Z'FEDCBA09',kind=REAL32),1_INT32)
   integer(kind=INT32) :: x2 = &
   &   transfer(real(Z'FFFFFFFF',kind=REAL32),1_INT32)
   print '(I0,1X,Z8.8)', x1, x1
   print '(I0,1X,Z8.8)', x2, x2
end program
Run Code Online (Sandbox Code Playgroud)

返回:

$ gfortran -o z file.f90
$ ./z
-19088887 FEDCBA09
2143289344 7FC00000
Run Code Online (Sandbox Code Playgroud)

注意: gfortran转换sNaNqNan,这是一个bug,但是没有人在乎。