32bit 64bit 格夫特兰:为什么-posinf";导致算术溢出?
为了在64位系统上获得+-inf,我使用了下面的代码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
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设置为任何精度都更加容易。但是,该模块中的几乎所有内容都只能在运行时使用,因此如果不使用十六进制文字,您仍然无法设置参数
常量。