32bit 64bit 格夫特兰:为什么-posinf";导致算术溢出?

32bit 64bit 格夫特兰:为什么-posinf";导致算术溢出?,32bit-64bit,ieee-754,gfortran,32bit 64bit,Ieee 754,Gfortran,为了在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

为了在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_算术模块,但gcc不处理它

是否有任何多体系结构方法可以将常数设置为正/负无穷大

更新 Gfortran选项
-fno范围检查
抑制错误并成功编译该代码

这不重要,但我还是很有趣。
为什么gfortran允许对+无穷大进行恒定的定义,但却大声喊出与-无穷大完全相同的东西

我没有使用与您相同的编译器(我使用的是
g95
,编译器选项
-i4
设置为32位整数,我发现的一个解决方法(如果您坚持使用
transfer
)是将整数参数指定为如下参数:

注意:在我的编译器中,我可以直接将数字分配给参数。我不确定你的参数是否相同,但我很确定你只应该在不真正处理常量的情况下使用传递函数——比如说,如果你在处理浮点数,并且需要真正的细节对其表示的控制权

注意变量
pdirect
ndirect

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

我希望这有帮助!

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

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

但同样的情况是,您的代码不符合Fortran标准,该标准规定十六进制文字只能出现在
data
语句或函数
int
real
、或
dble
中。但是,在
dble
中放入十六进制文字与
传输
的作用相同。如果gfortran中没有bug,您的程序可以运行,但在技术上是不正确的

无论如何,以下代码在gfortran中对我有效,我相信它将以符合标准的方式解决您的问题,并避免
-fno范围检查

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。)

谢谢!我编译了您的示例,得到了与问题中相同的错误。gfortran选项
-fno range check
抑制了错误并编译了我想要的内容。但我不喜欢这种解决方案。我仍然不明白为什么gfortran中的正无穷大和负无穷大之间存在如此大的差异。谢谢,它变得更清楚了。我我真的认为没有办法做到“干净”,也就是说用Fortran标准。这种带有十六进制常数的管道胶带只是因为gfortran中支持ieee-754的漏洞。它一定是有漏洞的。我用过的其他Fortran编译器(克雷、IBM、英特尔、NAG、PGI)所有模块都有
IEEE_算术
模块,这使得在运行时将无穷大或NaN设置为任何精度都更加容易。但是,该模块中的几乎所有内容都只能在运行时使用,因此如果不使用十六进制文字,您仍然无法设置
参数
常量。