1

在 64 位系统上获得 +-inf 我使用了下一个代码

double precision, parameter :: pinf           = transfer(z'7FF0000000000000',1d0) ! 64 bit
double precision, parameter :: ninf           = transfer(z'FFF0000000000000',1d0) ! 64 bit

它运作良好。

在 32 位上,我只有 ninf 的编译错误(!):

double precision, parameter :: ninf           = transfer(z'FFF0000000000000',1d0
                                                                           1     
Error: Integer too big for integer kind 8 at (1)

赋值 ninf = -pinf没有帮助并导致编译算术溢出错误:

double precision, parameter :: ninf           = -pinf
                                                         1
Error: Arithmetic overflow at (1)

我知道 ieee_arithmetic 模块,但 gcc 不处理它。

是否有任何多架构方法可以将常量设置为正/负无穷大?

更新 Gfortran 选项-fno-range-check抑制错误并成功编译该代码。

这不重要,但我仍然很有趣。为什么 gfortran 允许不断定义 +Infinity,但大声喊叫与 -Infinity 完全相同的东西?

4

2 回答 2

1

我没有使用与您相同的编译器(我正在使用为 32 位整数设置的g95编译器选项-i4,并且我发现的一种解决方法(如果您坚定地transfer为此目的使用)是指定整数参数作为这样的参数:

注意:使用我的编译器,我可以将数字直接分配给参数。我不确定它是否与您的相同,但我很确定您只有在不真正处理常量时才真正应该使用传递函数 - 就像您正在做花哨的事情一样浮点数,并且需要对其表示进行真正的细节控制。

注意变量pdirectndirect

program main
integer(8), parameter :: pinfx= z'7FF0000000000000'
integer(8), parameter :: ninfx= z'FFF0000000000000'
double precision, parameter :: pinf = transfer(pinfx, 1d0)
double precision, parameter :: ninf = transfer(ninfx, 1d0)

double precision, parameter :: pdirect = z'7FF0000000000000'
double precision, parameter :: ndirect = z'7FF0000000000000'


write (*,*) 'PINFX  ', pinfx
write (*,*) 'NINFX  ', ninfx
write (*,*) 'PINF   ', pinf
write (*,*) 'NINF   ', ninf
write (*,*) 'PDIRECT', pdirect
write (*,*) 'NDIRECT', ndirect

end program

这将产生输出:

 PINFX   9218868437227405312
 NINFX   -4503599627370496
 PINF    +Inf
 NINF    -Inf
 PDIRECT +Inf
 NDIRECT +Inf

我希望这有帮助!

于 2013-08-19T16:16:36.463 回答
1

在这种情况下,gfortran 在内部将您的十六进制(“Z”)文字表示为可用的最大无符号整数大小。由于transfer是 Fortran 内在函数,并且 Fortran 没有无符号整数,因此 gfortran 所做的第一件事是将文字分配给有符号类型,这会导致负无穷大的位模式溢出。这发生在您使用 BOZ 文字的许多其他情况下,我认为这是 gfortran 中的一个错误。

我认为这只出现在 32 位系统上,因为在您的 64 位系统上,gfortran 可能有 128 位整数类型可用;128 位有符号整数不会“溢出”该位模式。

但也有你的代码不符合 Fortran 标准的情况,该标准规定十六进制文字只能出现在data语句或函数int,realdble. 但是,将十六进制文字放入其中的dble作用与其他方法相同transfer。如果 gfortran 中没有错误,您的程序可以运行,但从技术上讲它是不正确的。

无论如何,以下代码在 gfortran 中对我有用,我相信它会以符合标准并避免的方式解决您的问题-fno-range-check

integer, parameter :: i8 = selected_int_kind(13)
integer, parameter :: r8 = selected_real_kind(12)
integer(i8), parameter :: foo = int(Z'7FF0000000000000',i8)
integer(i8), parameter :: bar = ibset(foo,bit_size(foo)-1)
real(r8), parameter :: posinf = transfer(foo,1._r8)
real(r8), parameter :: neginf = transfer(bar,1._r8)
print *, foo, bar
print *, posinf, neginf
end

输出:

  9218868437227405312    -4503599627370496
                  Infinity                 -Infinity

关键是首先创建正无穷大的模式(因为它有效),然后通过简单地设置符号位(最后一个)来创建负无穷大的模式。内在函数仅适用于整数,因此ibset您必须使用transfer这些整数来设置真正的正/负无穷大。

(我使用 i8/r8 只是习惯,因为我使用过种类参数不等于字节数的编译器。在这种情况下它们都等于 8。)

于 2013-08-20T06:12:31.663 回答