fortran 64位六角形BOZ

时间:2015-02-26 12:58:10

标签: c++ c fortran

在C ++中这是被接受的:

uint64_t mask = 0x7FC0000FF80001FFLL;

但是在fortran中

integer(kind=8), parameter :: mask = Z'7FC0000FF80001FF'

不适用于gfortan。 我认为它们都是64位值?不是吗?

gfortran抱怨道:

  

从INTEGER(16)转换为INTEGER(8)

的算术溢出



编辑:

所以,抱歉混淆,这里有一些更加扩展的问题描述。 我将在Fortran中进行一些转换,并在c ++中提供一些示例代码。 在示例c ++代码中,掩码定义如下:

typedef uint64_t mask;
static const mask dilate_2 = (mask)0x7FC0000FF80001FFLL ;
static const mask dilate_1 = (mask)0x01C0E070381C0E07LL ;
static const mask dilate_0 = (mask)0x9249249249249249LL ;

从我糟糕的c ++理解,我认为十六进制值是64位 整数值(它们在结尾处有LL)。 现在在Fortran我的问题首先是,用

定义
integer(kind=8), parameter ...  
弗拉基米尔说,

没有用,因为

integer(kind=8), ...

可能不是64位整数 比我测试的Alexanders解决方案,适用于第一个和第一个 第二(dilate_2,dilate_1)常数 弗拉基米尔解决方案也适用于这两个。
现在对于dilate_0,这些解决方案都不起作用。我认为弗拉基米尔解决方案将投射0x9249249249249249LL(实际上是什么 比INT64中允许的更大的整数到INT64中 如果我这样做:

integer(INT64), parameter :: dilate_0 = int(Z'9249249249249249', &
                             kind=kind(dilate_0)

但这也不起作用,gfortran给我一个错误:

  

错误:算术溢出在(1)处将INTEGER(16)转换为INTEGER(8)。

所以我的实际问题是如何在Fortran中实现这个常量?

3 个答案:

答案 0 :(得分:3)

正如弗拉基米尔在他的评论integer(kind=8)中发表的那样不可移植(而不是编译器抱怨的那种16)。

作为补救措施,我建议使用内部模块ISO_Fortran_env(Fortran 2003),它对于所使用的编译器有很多predefined constants。使用此模块中的INT64可以解决您的问题并生成可移植代码:

program test
  use,intrinsic :: ISO_Fortran_env, only: INT64
  integer(INT64), parameter :: mask = Z'7FC0000FF80001FF'

  print *,mask
end program

答案 1 :(得分:1)

Z'9249249249249249'无法表示为INT64(相当于gfortran中的INTEGER(kind=8))因为

  • BOZ常量是带符号的数字(与Fortran中的每个其他整数常量相同)
  • 此数字大于2 ** 63-1,是INT64的最大可表示数字
因此,Gfortran选择适合的最小整数类型,即INTEGER(KIND=16)

然后我们有参数staement,其中INTEGER(KIND=8)参数应该被赋予超出其范围的值。这就是编译器抱怨的内容。它会以同样的方式抱怨

  INTEGER(KIND=4), PARAMETER :: N = 37094947285

如果你想解决这个问题,你可以使用-fno-range-check选项来gfortran。有关-fno-range-check的信息已包含在gfortran错误消息中(您未显示的部分)。

答案 2 :(得分:0)

我会这样做以保持标准符合

  integer(whatever), parameter :: mask = int(Z'7FC0000FF80001FF', &
                                             kind=kind(mask))

其中whatever是所需值的某种常量。它可能是int64

如果常数对应于负数,则上述操作无效。然后必须制作一个技巧:

integer(int32), parameter :: mask = transfer(int(Z'A0000000',int64),1_int32)

integer(int32), parameter :: mask = transfer(Z'A0000000',1_int32)

但我不确定最后一个是否严格符合标准。